К основному контенту

Привет миру из Unreal Engine 4 на C++. Часть 2.

В прошлой части был создан класс актера для представления в игровом мире шара и надписи, в него добавлены  компоненты коллизии и меша. В этой части к классу актера будет добавлены компонент с эффектом огня и компонент для вывода текста. Также будут реализован делегат и события, чтобы добавить интерактивности огненному шару. А для того, чтобы шар выглядел как металлический, ему будет назначен соответствующий материал. Все эти шаги будет проделаны на С++.

Добавление компонента с эффектом огня UParticleSystemComponent.

Добавления этого компонента происходит подобно UStaticMeshComponent. Запишу в конструктор моего объекта следующий код:

// Create the fire particle system
UParticleSystemComponent* FireParticles = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("FireParticles"));
FireParticles->SetupAttachment(SphereVisual);
FireParticles->bAutoActivate = true;

// Assign fire particle system to component
ConstructorHelpers::FObjectFinder<UParticleSystem>FireVisual(TEXT("/Game/StarterContent/Particles/P_Fire.P_Fire"));
if (FireVisual.Succeeded())
{
    FireParticles->SetTemplate(FireVisual.Object);
}

С помощью CreateDefaultSubobject() создаем компонент UParticleSystemComponent и присоединяем его к ранее созданному компоненту меша UStaticMeshComponent, т.е. сделали его дочерним компонентом. Это делается для того, чтобы эффект огня перемещался вместе с мешем. Для того чтобы эффект огня появился сразу же после создания объекта в игровом мире было установлено свойство bAutoActivate. Далее был использован FObjectFinder для получения доступа к имеющемуся в стартовом контенте эффекту огня P_Fire. После проверки, что такой элемент существует, он через специальный метод был установлен в компонент UParticleSystemComponent.

После компиляции можно увидеть, что теперь шар стал гореть:


Добавление компонента TextRenderComponent для вывода 3D текста.

 Как и прошлые компоненты добавлю его в конструкторе актера:
// Initialize Text Render component
TextRenderComponent = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Text"));
TextRenderComponent->SetupAttachment(SphereVisual);
TextRenderComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 110.0f));
TextRenderComponent->SetHorizontalAlignment(EHTA_Center);
TextRenderComponent->SetYScale(2.0f);
TextRenderComponent->SetXScale(2.0f);
TextRenderComponent->SetVisibility(true);
TextRenderComponent->SetText(NSLOCTEXT("AnyNs", "Any", "HelloWorld"));
Компонент традиционно создается через функцию CreateDefaultSubobject(), которая возвращает указатель на этот новый компонент. Присоединим его к компоненту меша, чтобы надпись двигалась вместе с ним, после чего настроим расположение компоненты 3D текста, чтобы он был немного выше шара. Следующие методы устанавливают размер текста, возможность его отображения и сам текст "HelloWorld".

При установке текста был использован макрос NSLOCTEXT, он возвращает значение типа FText. Данный макрос используется для локализации текста. "AnyNs" - это пространство имен, а "Any" - ключ данного текста. При переводе текста на другой язык, он может изменится, но ключ останется тем же самым, а пространство имен используется для группировки ключей.

Теперь актер выглядит так:


Делегаты и события.

Необходимо реализовать сценарий, при котором при приближении к шару во время игры, менялась бы надпись с приветствия мира на приветствие приближающегося актера. В данном случае будет выведено имя текущего игрока, это возможно потому что Player наследуется от класса AActor.

Так как для коллизии шара были установлены правила при котором он должен реагировать на пересечение его коллизии, то в этот момент возбуждается событие OnActorBeginOverlap, а при выходе другого актера из коллизии шара возбуждается событие OnActorEndOverlap. Таким образом есть возможность назначить этим событиям обработчики в виде обычных методов класса и реализовать в них весь необходимый функционал.

Для этого в файл HelloSphere.h в раздел protected добавляю следующие методы:
protected:
    // On Overlap implementation
    UFUNCTION()
    void MyOnBeginOverlap(class AActor* OverlappedActor, class AActor* OtherActor);
    // On End Overlap implementation
    UFUNCTION()
    void MyOnEndOverlap(class AActor* OverlappedActor, class AActor* OtherActor);
А в файл HelloSphere.cpp их реализацию:
void AHelloSphere::MyOnBeginOverlap(AActor* MyOverlappedActor, AActor* OtherActor)
{
 FString outputString;
 outputString = "Hello " + OtherActor->GetName() + "!";
 TextRenderComponent->SetText(FText::FromString(outputString));
}

void AHelloSphere::MyOnEndOverlap(AActor* MyOverlappedActor, AActor* OtherActor)
{
 TextRenderComponent->SetText(NSLOCTEXT("AnyNs", "Any", "HelloWorld"));
}
В первой функции класса создается составная строка, для которой берется имя объекта актера, который пересек коллизию шара, указатель на этот объект передается из события. После чего устанавливается данный текст в компонент 3D текста.  Во второй функции, которая срабатывает при выходе игрка из коллизии шара, восстанавливает первоначальную надпись.

Теперь для того чтобы связать возбуждаемые события с этими функциями, необходимо в конструкторе шара AHelloSphere::AHelloSphere() написать следующие строки:

// Bind delegates
OnActorBeginOverlap.AddDynamic(this, &AHelloSphere::MyOnBeginOverlap);
OnActorEndOverlap.AddDynamic(this, &AHelloSphere::MyOnEndOverlap);

Здесь через AddDynamic(), событиям назначается ссылка на функции класса, которые необходимо вызывать во время возбуждения этих событий. Помимо AddDynamic() существуют и другие подобные функции.

После компиляции, при приближении к шару, надпись над ним меняется на другую:


Назначение материала шару через С++.

Для того чтобы изменить материал меша шара, нужно с помощью FObjectFinder найти нужный материал в проекте и установить его, через специальный метод, в компонент UStaticMeshComponent. Чтобы это сделать в данном проекте, необходимо немного изменить код в конструкторе, который создает и настраивает компонент меша.

Вот измененный участок кода из конструктора AHelloSphere::AHelloSphere():

// Create and attach a sphere mesh
UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereMesh"));
SphereVisual->SetupAttachment(RootComponent);
// Assign mesh to static mesh component through construction helper
ConstructorHelpers::FObjectFinder<UStaticMesh>SphereAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
ConstructorHelpers::FObjectFinder<UMaterial>SphereMaterial(TEXT("/Game/StarterContent/Materials/M_Metal_Burnished_Steel.M_Metal_Burnished_Steel"));
// Adjust properties of the mesh if mesh asset was found
if (SphereAsset.Succeeded() && SphereMaterial.Succeeded())
{
    SphereVisual->SetStaticMesh(SphereAsset.Object);
    SphereVisual->SetMaterial(0, SphereMaterial.Object);
    SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -50.0f));
}

В нем добавлена строка с новым FObjectFinder<UMaterial>, который ищет ассет с материалом по заданному пути, а затем в операторе if проверяется найден ли данный материал. После этого методом SetMaterial() назначается материал мешу. Первый параметр этого метода является индексом материала, он нужен для назначения нескольких материалов, если меш поддерживает больше одного материала.

Можно сказать, что проект разработанный исключительно на С++ завершен. Вот как выглядит завершенная программа:


Blueprints и C++. Часть 3.

Комментарии

Популярные сообщения из этого блога

Привет миру из Unreal Engine 4 на C++. Часть 1.

Почему С++, а не Blueprint? Просмотрел и прочитал много статей про программирование на блупринтах, чтобы выяснить их место в создании игр на движке Unreal Engine 4 и в чем их преимущество перед традиционным программирование на языке программирования С++. Как оказалось это не конкурирующие подходы, а дополняющие один другой, при том в продакшене используется большей частью С++. Сами разработчики движка из Epic для своих игр используют эти две составляющие на разных этапах разработки игры. Сначала на блупринтах геймдизайнеры создают прототип игры, затем передают его программистам, которые для продакшена переписывают игру уже на С++. А раз сами разработчики движка предпочитают выпускать игры на С++, а не на чистых блупринтах, то значит и другие должны поступать также. Само собой писать всё на С++ будет не правильно и нужно находить баланс между блупринтами и С++. Думаю это самый сложный момент, потому что по сути нет инструкций, когда надо использовать С++, а когда блупринты....