原文链接:http://orfeasel.com/actor-spawning/
Actor的生成和GetDefaultObject
有些时候我们需要在游戏运行时生成基于C++类的actor。另外,我们还需要了解函数GetDefaultObject的作用以及我们为什么应该了解它!让我们开始吧!
Actor的生成
在本文中我们将创建两个Actor。一个包含一些基础的逻辑(我们将这个Actor命名为UsefulActor),而另一个会在一段时间后生成UsefulActor。我们第一步先添加一个新的C++类(基于actor类),命名为UsefulActor然后在它的头文件中加入以下逻辑:
1. void DoSomething()
2. {
3. GLog->Log("UsefulActor does something...");
4. }
切换到你的编辑器,创建一个基于此类的蓝图,命名为BP_UsefulActor。记得要在你的蓝图中添加一个静态网格物体,这样当你的actor生成的时候你可以看见它。
设置完UsefulActor后,添加另一个名为ActorSpawner的C++类(它也继承自actor类)。在它的头文件中,包含UsefulActor.h然后加入以下代码:
1. /*Blueprint Reference of UsefulActor class*/
2. UPROPERTY(EditDefaultsOnly,Category="ActorSpawning")
3. TSubclassOf<AUsefulActor> UsefulActorBP;
4.
5. /*Delay after the Blueprint of the UsefulActor will get spawned*/
6. UPROPERTY(EditDefaultsOnly, Category = "ActorSpawning")
7. float TimeToSpawn = 2.f;
8.
9. /*Spawns the UsefulActor Blueprint*/
10. UFUNCTION()
11. void SpawnUsefulActor();
TSubclassOf意味着该性质可以接受任何AUsefulActor类型的对象。由于我们制作了一个基于此类的蓝图,我们可以将蓝图作为该性质中的一个参数。
记得要在ActorSpawner.generated.h之前包含“UsefulActor.h”。否则你的项目不会成功编译。
切换到ActorSpawner.cpp文件然后添加以下功能:
1. void AActorSpawner::BeginPlay()
2. {
3. Super::BeginPlay();
4.
5. FTimerHandle OutHandle;
6.
7. //Will call SpawnUsefulActor after the specified time
8. GetWorld()->GetTimerManager().SetTimer(OutHandle, this, &AActorSpawner::SpawnUsefulActor, TimeToSpawn);
9.
10. }
11. void AActorSpawner::SpawnUsefulActor()
12. {
13. //If the usefulactorbp is valid
14. if(UsefulActorBP)
15. {
16. //Spawn parameters for the current spawn.
17. //We can use this for a number of options like disable collision or adjust the spawn position
18. //if a collision is happening in the spawn point etc..
19. FActorSpawnParameters SpawnParams;
20.
21. //Actual Spawn. The following function returns a reference to the spawned actor
22. AUsefulActor* ActorRef = GetWorld()->SpawnActor<AUsefulActor>(UsefulActorBP, GetTransform(), SpawnParams);
23.
24. GLog->Log("Spawned the UsefulActor.");
25. }
26. }
编译你的代码然后创建一个基于ActorSpawner类的蓝图。然后打开它,在UsefulActorBP性质中选择BP_UsefulActor,不要选择UsefulActor类,如下图所示:
设置完成后,将ActorSpawner蓝图放置在你的关卡的某处然后点击播放/模拟按钮。BP_UsefulActor应该在蓝图中设置的 “Time To Spawn” 秒后生成。
Epic的API提供了一些有用的SpawnActor函数的重载,你可以在这里找到它们。
我们在UsefulActorBP性质中选择蓝图类而不是C++类的原因是我们想要生成蓝图而不是C++类。尽管我们的蓝图是基于C++类的,但我们将一些特定的数值存储在了蓝图中而不是在C++中,比如我们上文添加的静态网格物体。在实际项目中也有可能遇到这种情况。大部分情况下,你要创建一个基于C++类(其中包含一些自定义的性质)的actor。然后,切换到你的编辑器并为这些性质赋值。这样当你想要生成拥有所有设置好性质的actor时你应该选择蓝图版本的而不是C++类的。
GetDefaultObject
在前面例子中,当我们生成一个新的actor时我们储存了一个指针的引用。假设我们忘记储存该引用,后来我们想要使用AUsefulActor类中的DoSomething函数。也许你认为这很简单。由于我们储存了UsefulActorBP,我们只需使用它调用DoSomething函数。但是当你键入以下代码后:
UsefulActorBP->DoSomething();
你的代码不能正确编译。你会得到以下错误:
嗯,这就怪了!虽然TSubclassOf接受任何AUsefulActor的派生类,但是我们不能使用任何C++函数。这里就要用到GetDefaultObject了。该函数会得到我们上面使用的子类(其中含有C++函数)的父类。所以以下代码将正确编译和执行:
UsefulActorBP->GetDefaultObject<AUsefulActor>()->DoSomething();
另一种取得AUsefulActor的C++函数的使用权限的方法是将蓝图转换成它的父类。但是类型转换在性能方面通常需要很大的开销。