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

Привет миру из 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.

Комментарии

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

Создание делегата, который связан с UFUNCTION.

Делегаты позволяют нам вызывать функцию не знаю какая именно назначена функция. Они являются безопасной версией указателя на функцию. Здесь будет разобрано как ассоциировать UFUNCTION с делегатом, чтобы она вызывалась, когда он выполняется. Чтобы получился этот пример, необходимо использовать проект с классом TriggerVolume из прошлой статьи . Как это сделать... Внутри заголовочного файла  GameMode объявить делегат с помощью специального макроса, который нужно написать над  UCLASS() : DECLARE_DELEGATE(FStandardDelegateSignature) UCLASS() class EVENT_API AEventGameModeBase : public AGameModeBase Добавить новый член класса в GameMode : FStandardDelegateSignature MyStandardDelegate; Создать в редакторе движка новый класс Actor , назвав его  DelegateListener . И добавить в заголовочный файл нового класса следующие объявления: UFUNCTION() void EnableLight(); UPROPERTY() UPointLightComponent* PointLight; В конструктор класса, надо добавить код для создания ...