NOTE 食用此文章的前提是已经看过迪迪老师的UE4教程UE4全反射零耦合框架开发坦克游戏
NOTE 本文放到博客里宽度有点容不下,可以复制到Markdown中观看
如果你是UE4新手,相信突然从框架开发转为用框架开发游戏都有点不适应吧,鉴于迪迪老师目前还没有出DataDriven框架的实战教程。而现在又想要用框架做开发。现在JFor就带你们从零开始使用DataDriven提供的功能搭建一款游戏。
再来说一下整个框架的生命周期是如何与UE4的Actor相配合的:
我们知道DDDriver是继承自AActor的,所以只要将其蓝图实例拖进场景,它就开始了它完整的UE4的Actor的生命周期,而整个DataDriven框架的生命周期就是由DDDriver的生命周期驱动的:
具体而言,涉及到四个函数:
ADDDriver();
virtual void PostInitializeComponents() override;
virtual void BeginPlay() override;
挨个看:
构造函数ADDDriver()作用:
实例化根组件 RootScene
实例化中央模组组件 Center
就是我们图片中看到的黄色的这两个:
PostInitializeComponents()中的动作:
注册自己到DDCommon
[DDDriver] UDDCommon::Get()->InitDriver(this);
填充所有模组组件的子模组数据ChildModule,同时对照枚举设定每个模组组件的模组ID,ModuleIndex
[DDDriver] Center->IterChangeModuleType(Center, ModuleType)
[DDCenterModule] Module->ChangeModuleType(ModType); #递归
[DDModule]
获取所有的模组组件,并按照每个模组的模组ModuleIndex的顺序填充到Center的所有模组组件数组ModuleGroup中
[DDDriver] Center->TotalGatherModule(ModuleType);
[DDCenterModule] GatherGroup.Push(Module); #递归
所有模组组件的DDMessage,DDModel,DDWealth的创建
[DDDriver] Center->IterCreateManager(Center);
[DDCenterModule] Module->CreateManager(); #递归
UDDModule::CreateManager()中的动作:
实例化Model组件
实例化Message组件
实例化Wealth组件
避免销毁Model组件
避免销毁Message组件
避免销毁Wealth组件
为Model指定模组
[DDModule] Model->AssignModule(this);
[DDMM]/[DDModel]
为Message指定模组
[DDModule] Message->AssignModule(this);
[DDMM]/[DDMessage]
为Wealth指定模组
[DDModule] Wealth->AssignModule(this);
[DDMM]/[DDWealth]
BeginPlay()中的动作:
注册GamePlay到框架(将GameInstance以及PlayerController注册到框架)
[DDDriver] RegisterGamePlay();
调用所有模组所有组件所有对象的Init函数
[DDDriver] Center->IterModuleInit(Center);
[DDCenterModule] Module->ModuleInit(); #递归
UDDModule::ModuleInit()中的动作:
调用Model的Init函数
[DDModule] Model->ModelInit();
[DDModel] 暂时什么也没有做
调用Message的Init函数
[DDModule] Message->MessageInit();
[DDMessage] 暂时什么也没有做
调用Wealth的Init函数
[DDModule] Wealth->WealthInit();
[DDWealth] 暂时什么也没有做
Tick(float DeltaTime)中的动作:
第一帧运行所有模组所有组件所有对象的BeginPlay函数
[DDDriver] Center->IterModuleBeginPlay(Center);
[DDCenterModule] Module->ModuleBeginPlay(); #递归
UDDModule::ModuleBeginPlay()中的动作:
给Wealth指定资源
[DDModule] Wealth->AssignData(WealthData);
[DDWealth]
调用Model的BeginPlay函数
[DDModule] Model->ModelBeginPlay();
[DDModel] 暂时什么也没有做
调用Message的BeginPlay函数
[DDModule] Message->MessageBeginPlay();
[DDMessage] 从UDDCommon获取Controller
调用Wealth的BeginPlay函数
[DDModule] Wealth->WealthBeginPlay();
[DDWealth] 根据前面指定的资源,生成Object对象,Actor对象,Widget对象
第二帧开始循环运行所有模组所有组件所有对象的Tick函数
[DDDriver] Center->IterModuleTick(Center, DeltaTime);
[DDCenterModule] Module->ModuleTick(DeltaSeconds);
UDDModule::ModuleTick(float DeltaSeconds)中的动作:
调用Model的Tick函数
[DDModule] Model->ModelTick(DeltaSeconds);
UDDModel::ModelTick(float DeltaSeconds)中的动作:
调用对象的Tick函数
[DDModule] ObjectTickGroup[i]->DDTick(DeltaSeconds);
[DDOO]/[xxx] DDTick(float DeltaSeconds)
调用ActiveLife函数从而一次一个地执行对象Tick函数之前的生命周期函数
[DDModule] ObjectActiveGroup[i]->ActiveLife()
IDDOO::ActiveLife()中的动作:
调用对象的Init函数
[DDOO]/[xxx] DDInit();
调用对象的Loading函数
[DDOO]/[xxx] DDLoading();
调用对象的Register函数
[DDOO]/[xxx] DDRegister();
调用对象的Enable函数
[DDOO]/[xxx] DDEnable();
调用对象的Release函数
[DDModule] ObjectReleaseGroup[i]->DDRelease();
[DDOO]/ 注销所有协程, 延时以及按键事件
调用对象的Destroy函数从而一次一个地执行对象Release函数之前的生命周期函数
[DDModule] ObjectDestroyGroup[i]->DestroyLife()
IDDOO::DestroyLife()中的动作:
调用对象的DDDisable函数
[DDOO]/[xxx] DDDisable();
调用对象的DDUnRegister函数
[DDOO]/[xxx] DDUnRegister();
调用对象的DDUnLoading函数
[DDOO]/[xxx] DDUnLoading();
调用Wealth的Tick函数
[DDModule] Wealth->WealthTick(DeltaSeconds);
[DDWealth] 处理各种类型的 资源加载栈
调用Message的Tick函数
[DDModule] Message->MessageTick(DeltaSeconds);
[DDMessage] 处理协程系统 和 延时系统
总结:
BeginPlay函数之前
在BeginPlay函数之前进行的是DataDriven框架的创建工作,将顶层DDDriver与第二层DDModule, 第二层DDModule与第三层 DDModel、DDMessage、DDWealth的框架进行了创建。
BeginPlay函数
在BeginPlay函数之中进行的是第二层DDModule以及第三层DDModel、DDMessage、DDWealth的Init工作,不过初始化的内容暂时是空的。(一些对象实例因为也是在场景中,所以其BeginPlay函数会在同一时间被调用,其中有注册到框架的调用)
Tick函数的第一帧
在Tick函数的第一帧进行的是第二层DDModule以及第三层DDModel、DDMessage、DDWealth的BeginPlay工作,主要是DDWealth将一些对象资源注册到框架。
Tick函数的第二帧及以后