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,如果经测试性能有提高可以保持关闭