AActor 的创建流程可以梳理为以下五个核心阶段。
这个流程确保了 Actor 从内存中的一块数据,逐步变成一个拥有组件、能参与物理碰撞、并能执行游戏逻辑的实体。
1. 实例化阶段 (Instantiation)
入口:UWorld::SpawnActor 或 NewObject<AActor>。
动作:
分配内存并调用 构造函数 (Constructor)。
设置基础属性(如 Instigator, Owner, NetRole)。
如果使用了 bDeferConstruction,此时会暂停构建,等待后续手动调用 FinishSpawning。
2. 注册与初步回调 (Registration & Post-Create)
函数:PostActorCreated()
时机:在 Actor 刚被生成,但还没有开始初始化组件时调用。
作用:这是 Actor 生命周期的第一个“可执行代码”入口。通常用于一些不依赖组件存在的纯逻辑初始化。
3. 组件组装与构建 (Construction)
函数:FinishSpawning() -> ExecuteConstruction()
动作:
执行构造脚本:运行 C++ 和蓝图中的 Construction Script。
组件创建:根据脚本生成所有的 UActorComponent。
根节点确立:确定 RootComponent 并设置初始变换(位置/旋转)。
OnComponentCreated:每个新生成的组件都会收到此通知。
4. 组件初始化 (Component Initialization) —— 关键链路
这是你在 Actor.cpp 注释中看到的核心部分:
PreInitializeComponents():
在组件正式初始化前调用。AGameModeBase 就是在这里生成了 GameState。
IncrementalRegisterComponents():
将所有组件注册到世界中,使它们能被渲染和物理引擎识别。
InitializeComponent():
遍历每个组件,调用其各自的初始化逻辑。
PostInitializeComponents():
所有组件都准备好后调用。此时你可以安全地获取任何组件的引用。
5. 进入游戏世界 (Begin Play)
函数:DispatchBeginPlay() -> [BeginPlay()]
时机:当关卡正式开始运行(World->HasBegunPlay() 为真)时触发。
动作:
注册 Tick 函数(如果开启了 Tick)。
处理初始的重叠事件(Overlaps)。
调用蓝图的 Event BeginPlay。
对于 GameMode,随后会调用 [StartPlay()] 通知 GameState 比赛开始。
总结:AActor 生命周期速查表
阶段 关键函数 状态特征
出生 Constructor 内存已分配,但还没进世界。
落地 PostActorCreated 进了世界,但组件还没动工。
装修 ExecuteConstruction 蓝图/脚本运行,组件全部挂好。
通电 Pre/PostInitializeComponents 组件注册完毕,内部逻辑启动。
开业 [BeginPlay] 游戏正式开始,可以接收输入和 Tick。
为什么理解这个顺序很重要? 因为在 Constructor 里你不能调用 GetWorld()(可能为空),在 PreInitializeComponents 之前你不能访问其他组件(因为它们还没初始化)。Lyra 框架正是利用了这个严格的顺序,通过 InitState 机制来管理这些异步的初始化步骤,确保角色在“开业”前所有“设备”都已通电。