UE5 Actor 生命周期
一图流
从磁盘加载
从磁盘加载(Load from disk) 路径适用于已经在关卡中的Actor,如当UEngine::LoadMap发生时,或当关卡流送调用UWorld::AddToWorld时
个人理解:对于打包发布后的游戏,每张地图上的默认物品,例如放置的树,建筑,道路等都以这种方式加载
整体流程:
- 从磁盘加载包/关卡中的Actor
- 序列化的Actor从磁盘加载完成后调用PostLoad。所有自定义版本化和修复操作应在此处进行。PostLoad与AActor::PostActorCreated互斥
- 世界调用UAISystemBase::InitializeActorsForPlay,以准备Actor启动GamePlay
- 关卡为任何没有初始化的Actor和seamless travel carry-over调用Ulevel::RouteActorIntialize,以下为此过程调用的函数- AActor::PreInitializeComponent在- InitializeComponent调用前被调用
- UActorComponent::InitiializeComponent是在Actor上的每一个Component创建时的帮助函数
- AActor::PostInitializeComponent在Actor的所有Component初始化完毕后调用
 
- 当关卡开始运行后,调用AActor::BeginPlay函数
在编辑器中运行
从编辑器中运行时,Actor是从编辑器中直接复制到世界场景中,而不是从磁盘进行加载,整体初始化流程与从磁盘加载类似
- Actor被从编辑器复制到新的世界场景中
- Actor调用UObject::PostDumplicate
- 世界场景调用UAISystemBase::InitializeActorsForPlay
- 关卡为任何没有初始化的Actor和seamless travel carry-over调用Ulevel::RouteActorIntialize,以下为此过程调用的函数- AActor::PreInitializeComponent在- InitializeComponent调用前被调用
- UActorComponent::InitiializeComponent是在Actor上的每一个Component创建时的帮助函数
- AActor::PostInitializeComponent在Actor的所有Component初始化完毕后调用
 
- 当关卡开始运行后,调用AActor::BeginPlay函数
生成
生成Actor时遵循以下流程
- UWorld::SpawnActor被调用
- AActor::PostSpawnInitialize在Actor生成到世界场景中后被调用
- AActor::PostActorCreated被调用,任何构造函数的实现应该在这里进行,与- PostLoad冲突
- AActor::ExecuteConstructor
- AActor::OnConstructor蓝图Actor的Component和变量在这里被创建和初始化
- AActor::PostActorConstructor:- AActor::PreInitializeComponent
- UActorComponent::InitializeComponent
- AActor::PostInitializeComponent在Component初始化结束后被调用
 
- UWorld::OnActorSpawned广播到UWorld
- 调用AActor::BeginPlay
补充:第一步UWorld::SpawnActor源码,其中SpawnActor在LevelActor.cpp中实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
template< class T >  
T* SpawnActorDeferred(  
    UClass* Class,  
    FTransform const& Transform,  
    AActor* Owner = nullptr,  
    APawn* Instigator = nullptr,  
    ESpawnActorCollisionHandlingMethod CollisionHandlingOverride 
	    = ESpawnActorCollisionHandlingMethod::Undefined,  
    ESpawnActorScaleMethod TransformScaleMethod 
	    = ESpawnActorScaleMethod::MultiplyWithRoot  
    )  
{  
    if( Owner )  
    {  
       check(this==Owner->GetWorld());  
    }  
    FActorSpawnParameters SpawnInfo;  
    SpawnInfo.SpawnCollisionHandlingOverride = CollisionHandlingOverride;  
    SpawnInfo.TransformScaleMethod = TransformScaleMethod;  
    SpawnInfo.Owner = Owner;  
    SpawnInfo.Instigator = Instigator;  
    SpawnInfo.bDeferConstruction = true;  
    return (Class != nullptr) 
	    ? Cast<T>(SpawnActor(Class, &Transform, SpawnInfo)) : nullptr;  
}
在LevelActor.cpp中,经过了大量的检查和配置,最终生成Actor的是这一行代码
1
2
3
4
5
6
7
8
9
// actually make the actor object  
AActor* const Actor = NewObject<AActor>(LevelToSpawnIn, 
					Class, 
					NewActorName, 
					ActorFlags, 
					Template, 
					false/*bCopyTransientsFromClassDefaults*/, 
					nullptr/*InInstanceGraph*/, 
					ExternalPackage);
接下来是上述流程中的事件
1
2
3
4
5
6
7
8
9
10
// Broadcast delegate before the actor and its contained components are initialized  
OnActorPreSpawnInitialization.Broadcast(Actor);
Actor->PostSpawnInitialize(UserTransform, 
						   SpawnParameters.Owner, 
						   SpawnParameters.Instigator, 
						   SpawnParameters.IsRemoteOwned(), 
						   SpawnParameters.bNoFail, 
						   SpawnParameters.bDeferConstruction, 
						   SpawnParameters.TransformScaleMethod);
延迟生成
一个具有生成时公开属性的Actor可以被延迟生成
注意:此处特指蓝图对象,在C++中,应直接使用
UWorld::SpawnActorDeffered
蓝图
假设有一个名为BP_LandBuilding的蓝图Actor,并且这个蓝图Actor有一个名为BaseScal的变量,这个变量设置为生成时公开且可编辑实例,则BaseScale的细节面板应如图所示
在调用SpawnActor蓝图节点生成此蓝图Actor时,将可以设置BaseScale的值
C++
在C++中使用延迟生成,应使用下方代码
1
2
3
const auto YourActor = GetWorld()->SpawnActorDeferred<YourClass>(YourClass, FTransform::Identity);  
// Do Something 在此处进行任何需要的设置操作
YourActor->FinishSpawning(FTransform::Identity);
Actor 生命周期的结束
在游戏中有几种销毁(Destroy)Actor的方式,但是Actor最终被从世界场景中移除(Removed)的方法是相同的,在游戏过程中,可以使用以下几个函数,但实际上许多Actor实际并不会在游戏过程中被销毁
- AActor::Destroy当游戏在任何时候需要移除Actor时,手动调用 AActor::Destroy ,但Gameplay仍在继续。Actor被标记为等待销毁并从关卡的Actor数组中移除
- AActor::EndPlay 在数个地方调用,旨在保证Actor的生命走向终点。在游戏过程中,如果包含Actor的流送关卡被卸载,Destroy将调用此方法和关卡过渡(Level Transitions)
- 调用EndPlay的全部情形- 显式调用Destroy
- 手动终止在编辑器中运行
- 关卡过渡(Seamless Travel 或 加载地图)
- 包含Actor的流送关卡被卸载
- Actor的生命周期已过
- 应用程序被关闭
- 无论这些情形出现的方式如何,Actor都将被标记为 RF_PendingKill,因此在下个垃圾回收周期中,UE会将其从内存中解除分配。此外,可以考虑使用更清洁的FWeakObjectPtr<AActor>代替手动检查”等待销毁”
 
- 显式调用
- AActor::OnDestroyed - 这是对Destroy的旧有反应。我们推荐你将此处的逻辑移到EndPlay,因为会由关卡过渡和其他游戏清理函数调用
垃圾回收
一个对象被标记待销毁的一段时间后,垃圾回收会将其从内存中移除,释放其使用的资源。
在销毁过程中,调用以下函数:
- UObject::BeginDestroy - 对象可利用此机会释放内存并处理其他多线程资源(即:图像线程代理对象)。与销毁相关的大多数Gameplay功能理应在EndPlay中更早地处理。
- UObject::IsReadyForFinishDestroy - 垃圾回收过程将调用此函数,以确定对象是否可以永久解除分配。返回false,此函数即可延迟对象的实际销毁,直到下一个垃圾回收过程。
- UObject::FinishDestroy - 最后,对象将被销毁,这也是释放内部数据结构的机会。这是内存释放前的最后一次调用。
高级垃圾回收
用处不大,在项目设置(Project Settings) 中的 垃圾回收(Garbage Collection) 部分下,可将 创建垃圾回收器UObject群集(Create Garbage Collector UObject Clusters) 选项设为 false,如果经测试性能有提高可以保持关闭


