Actor Spawning and GetDefaultObject С++

Иногда нам нужно создавать акторы прямо во время игры, которые основаны на классах С++. Кроме того мы посмотрим что делает функция GetDefaultObject и почему вы должны знать об этом! Давайте начнем!

ActorSpawning
Для этого поста, мы создадим два актора. Один будет содержать некоторую фиктивную логику, только ради этого поста (давайте назовем его UsefulActor). Первый шаг, добавить С++ класс основанный на классе Actor, названный UsefulActor и тип следующей логики в файле заголовке(.h):

Code


void DoSomething()
{
GLog->Log("UsefulActor does something...");
}

[свернуть]
Перейдите в Editor, и создайте Blueprint основанный на этом классе с именем BP_UsefulActor. Убедитесь в том, что добавили статический меш в вашем Blueprint для того чтобы вы могли понять заспавнился ли ваш актор.
После того, как мы закончили с UsefulActor, добавьте еще один С++ класс с именем ActorSpawner (который наследуется от класса Actor) Внутри его заголовочного файла, подключаем UsefulActor.h и вводим следующий код:
Code


/*Blueprint Reference of UsefulActor class*/
UPROPERTY(EditDefaultsOnly,Category="ActorSpawning")
TSubclassOf UsefulActorBP;

/*Delay after the Blueprint of the UsefulActor will get spawned*/
UPROPERTY(EditDefaultsOnly, Category = "ActorSpawning")
float TimeToSpawn = 2.f;

/*Spawns the UsefulActor Blueprint*/
UFUNCTION()
void SpawnUsefulActor();

[свернуть]
TSubclassOf означает, что это свойство может принимать любой объект типа AUsefulActor. Так как мы сделали Blueprint основанный на этом классе, мы можем передать Blueprint как параметр в этом свойстве.
Убедитесь в том что подключили UsefulActor.h перед ActorSpawner.generated.h ! В противном случае проект не будет компилироваться.
Перейдите в файл ActorSpawner.cpp и добавьте следующие функциональные возможности:
Code


void AActorSpawner::BeginPlay()
{
Super::BeginPlay();

FTimerHandle OutHandle;

//Will call SpawnUsefulActor after the specified time
GetWorld()->GetTimerManager().SetTimer(OutHandle, this, &AActorSpawner::SpawnUsefulActor, TimeToSpawn);

}
void AActorSpawner::SpawnUsefulActor()
{
//If the usefulactorbp is valid
if(UsefulActorBP)
{
//Spawn parameters for the current spawn.
//We can use this for a number of options like disable collision or adjust the spawn position
//if a collision is happening in the spawn point etc..
FActorSpawnParameters SpawnParams;

//Actual Spawn. The following function returns a reference to the spawned actor
AUsefulActor* ActorRef = GetWorld()->SpawnActor(UsefulActorBP, GetTransform(), SpawnParams);

GLog->Log("Spawned the UsefulActor.");
}
}

[свернуть]
Скомпилируйте код и создайте Blueprint, основанный на классе ActorSpawner который мы только что создали. Затем откройте Blueprint и в свойстве UsefulActorBP, добавьте BP_UsefulActor, а не класс UsefulActor, как предполагает следующее изображение.
Image

[свернуть]
Когда вы закончите с этим, поместите ActorSpawner Blueprint где то на вашем уровне и нажмите Play. BP_UsefulActor должке появляться после того, как указанный «Time To Spawn» закончится.
API от Epic предоставляет некоторые полезные функции SpawnActor. (ссылка на оригинальной странице)
Мы выбрали именно класс Blueprint вместо класса С++ в свойстве UsefulActorBP, потому что мы хотим создавать на уровне именно Blueprint актора а не класс C++. Даже если наш Blueprint основан на C++ мы храним определенные значения в Blueprint а не внутри класса, например StaticMesh который мы добавили. Так поступают и в реальных проектах. В большинстве случаев, вы будете создавать актор, основанный на классе С++, который имеет некоторые пользовательские свойства. Затем переключитесь на Editor, и заполните эти свойства. Так что, если вы хотите, чтобы создавался конкретный Актор со всеми свойствами что вы указали, вы выберете Blueprint вместо С++ класса.

GetDefaultObject

В предыдущем примере, когда мы заспавнили наш новый актор, мы сохранили ссылку на указатель. Давайте предположим, что мы забыли его сохранить, и теперь нам необходимо получить доступ к функции DoSomething(), которая постоянно находится в классе AUsefulActor. Вы можете подумать что это довольно просто. Так как мы имеем UsefulActorBP мы можем получить доступ к функции прямо оттуда. Но, когда вы вводите следующую строку кода:

UsefulActorBP->DoSomething();

Ваш код не будет компилироваться. И ошибка которую вы получите, будет следующей:

Image

[свернуть]
Хм, это странно! Даже несмотря на то что TsubclassOf принимает любой производный класс, мы не можем использовать какие либо С++ функции из AUsefulActor. Это тот случай когда нам пригодится GetDefaultObject. Эта функция позволяет получить родительский класс подкласса который мы использовали выше (где С++ функции «reside»). Таким образом следующая строка решит проблему, и мы сможем скомпилировать проект:

UsefulActorBP->GetDefaultObject()->DoSomething();

Альтернативный способ получения доступа к С++ функции AusefulActor это использовать Cast. Тем не менее, это может как правило оказаться «дорогой» операцией с точки зрения производительности.


Читайте также: