蓝图转CPP备忘录

0. 基本知识(官方教程:将蓝图转换为C++)
https://dev.epicgames.com/community/learning/courses/re6/unreal-engine-c/z4EJ/unreal-engine-c

1.处理蓝图中特有的异步调用
需要处理的异步调用如下:
Delay
SetTimer
Once
Timeline
PlayMontage

1.1 Delay 可被SetTimer替换
1.2 SetTimer 在CPP中 还支持 StaticDelegate(FTimerDelegate), 可以使用 FTimerDelegate::CreateLambda 来简化代码编写。
1.3 Once 需要完全重新实现一套CPP版本,UE本身无现成C++代码可利用。
1.4 PlayMontage 需要修改Engine代码,将 CreatePlayMontageProxy 暴露出来。

2.处理蓝图中的接口
原则:保持蓝图中的蓝图接口,转发给C实现的接口。
理由:
    1.存在大量Cast操作,不可能全工程去修改这些地方,也没必要。
    2.修改蓝图接口名称也会带来同等规模的关联代码修改。

3. 在蓝图中提炼函数
Collapse to Function
Collapse to Macro
Collapse Nodes

3.1 Once在蓝图Function中不生效
3.2 Timeline 无法提炼成 Function 或 Macro
3.3 Collapse Nodes 生成的叫做 Event subgraph, 但并不是"Event", 它在Function/Macro里也叫这个名字。
3.4 Collapse Nodes 一旦创建,无法在 "My Blueprint Window"中调整顺序,提前创建一大堆,按需改名。
3.5 Add Comment... Comment的Undo有bug,被不小心 Contain 其中的 Nodes 无法通过 Undo操作 脱离CommentArea。

4. 同名
4.1 函数同名
修改蓝图函数名,保留CPP函数名,会有编译错误来发现所有需要修改的地方。
对于override形式的蓝图函数,参考《2.处理蓝图中的接口》。

4.2 变量同名
修改CPP变量名,加后缀"_C"用于区分。保留蓝图变量名,因为变量过于琐碎。
不同名的CPP变量,不用加 "_C",因为只有 variables for config 才需要暴露到蓝图, 内部变量和计算变量不需要暴露。

5. 处理Override
大部分是蓝图事件, 使用 BlueprintImplementableEvent标注,可以采用三种方式Override.
5.1 子类使用 virtual XXX_Implementation; 开启类族中蓝图事件的override链.
5.2 查找调用处,一般有配套的FDelegate系列接口,用于给类族外的情况提供timing.
5.3 挑选合适的基类virtual函数,直接override. 在Super::XXX() 之后插入自定义代码.
个人感觉三种方式从效率上来讲没有太多差别。
5.1 更贴近蓝图和既有流程。
5.2 在类族内使用有点异端。
5.3 更复杂,有些炫技成分,并且新的override链也会形成一套额外的记忆负担。

6. 处理Public
6.1 Event 默认是public的,一些结构性Event(Sync结构只能存在于Event里)目前不知道如何限制其访问性
用"PrivateEvent_XXXX"前缀,解决一般性的 Private Event.
用"XXX_Event_0"后缀,解决 DynamicDelegate Event.
6.2 Function 可以精确控制Accessbility。 可以只有private和protected函数,没有public函数, 只通过Event来对外进行暴露。
转换结束时,应该没有,或少量 public 函数。

7. 处理Varibles
改造的抓手主要靠Event和Function. 变量只有三种用途:
7.1 构建性:组成部分,结构性需要,按需声明,基本上遵循"组合模式"。
7.2 运行时:为逻辑信息传递而存在的变量。
7.3 编辑态:需要进行配置的变量,可以通过Configuration机制走,也可以归类到一个UStruct里,便于识别和管理。

8.1 创建Component
为了达成等效于BP中通过编辑器提供的AddComponent按钮添加的组件,需要在 OnConstruction 之后创建需要的Component;
在构造函数里创建Components时,CPP父类中"聚合(如Controller)"及蓝图(SCS)中"创建"的组件都还不存在。

动态创建Actor全流程:(entry-1)
【UWorld(LevelActor.cpp)】 SpawnActor []
【UWorld(LevelActor.cpp)】 OnActorPreSpawnInitialization [delegate]
【AActor】 PostSpawnInitialize []
    【AActor】 DispatchOnComponentsCreated [static]
    【AActor(NoDefered)】 RegisterAllComponents [virtual]
        【AActor】 PreRegisterAllComponents [virtual]
        【AActor】 IncrementalRegisterComponents []
            【UActorComponent】 RegisterComponentWithWorld [virtual]
                【UActorComponent】 OnComponentCreated [virtual]
                【UActorComponent】 ExecuteRegisterEvents
                    【UActorComponent】 OnRegister
                    【UActorComponent】 CreatePhysicsState
                        【UActorComponent】 OnCreatePhysicsState [virtual]
            【UActor】 PostRegisterAllComponents [virtual]
    【AActor】 PostActorCreated [virtual]
    【AActor】 FinishSpawning []
        【AActor】 ExecuteConstruction []
            【USimpleConstructionScript】 ExecuteScriptOnActor [] << Create ActorComponents in blueprint
            【UBlueprintGeneratedClass】 CreateComponentsForActor [static] << Create TimelineComponents in blueprint
            【AActor(Defered)】 RegisterAllComponents [virtual]
            【UBlueprintGeneratedClass】 USimpleConstructionScript::RegisterInstancedComponent
            【AActor】 ProcessUserConstructionScript []
            【UBlueprintGeneratedClass】 BindDynamicDelegates
            【AActor】 OnConstruction [virtual] <<<<(all components created, both cpp and bp)
        【AActor】 PostActorConstruction []
            【AActor】 PreInitializeComponents [virtual]
            【APlayerController】 Possess [virtual]
            【AActor】 InitializeComponents []
                【UActorComponent】 Activate
                【UActorComponent】 InitializeComponent
            【AActor】 PostInitializeComponents [virtual]
            【AActor】 DispatchBeginPlay []

自身所有组件的容器:
OwnedComponents
    ReplicatedComponents
    InstanceComponents
    BlueprintCreatedComponents
添加组件到自身容器的方法:
AddComponentByClass
    FinishAddComponent

编辑器中组件被初始化的及时(不完整)
【FScriptIntegrationObjectHelper】 PostConstructInitObject [static]
【FObjectInitializer】 PostConstructInit
PostInitProperties()
ResetOwnedComponents
OwnedComponents

放置在关卡中的Actor创建全流程(entry-2)(不完整)
【UObject】 PostLoad [virtual]
    【UObject】 PostLoadSubobjects
        【AActor】 ResetOwnedComponents

8.2 复制到Client的Actor的创建过程
【UActorChannel】 bSpawnedNewActor = Connection->PackageMap->SerializeNewActor(Bunch, this, NewChannelActor);
【UPackageMapClient】 Actor = World->SpawnActorAbsolute(Archetype->GetClass(), FTransform(Rotation, SpawnLocation), SpawnInfo);
【UWorld】 SpawnActorAbsolute
【UWorld】 SpawnActor, 下同 动态创建Actor全流程:(entry-1)

8.2.1 GameState的复制
GameState 会在 PlayerStart之后创建,也是之后被复制到客户端, 因此如果涉及到对象创建的控制变量,不能放在某个AActor里,要放在LevelScriptActor级别。

9. EditAnyWhere/VisibleAnyWhere的坑
BP实例的字段在EditAnyWhere时被修改了值,会存到uasset文件里,如果之后再变更为VisibleAnyWhere,即使修改cpp里字段的默认值,也影响不到它。
因为 BPInstance Property 和 CDO Property 是两码事。

你可能感兴趣的:(UnrealEngine,unreal,engine)