Explorar o código

feat: 添加 LoadTree 的过程解释

NiceTry12138 hai 5 meses
pai
achega
94fadcc5b4
Modificáronse 4 ficheiros con 69 adicións e 1 borrados
  1. BIN=BIN
      UE5/AI/Image/001.png
  2. BIN=BIN
      UE5/AI/Image/002.png
  3. BIN=BIN
      UE5/AI/Image/003.png
  4. 69 1
      UE5/AI/README.md

BIN=BIN
UE5/AI/Image/001.png


BIN=BIN
UE5/AI/Image/002.png


BIN=BIN
UE5/AI/Image/003.png


+ 69 - 1
UE5/AI/README.md

@@ -22,4 +22,72 @@ UBehaviorTreeManager* UBehaviorTreeManager::GetCurrent(UWorld* World)
 const bool bLoaded = BTManager->LoadTree(TreeAsset, RootNode, InstanceMemorySize);
 ```
 
-在 `LoadTree` 的时候会通过
+通过 `LoadTree` 函数或者该行为树实例所占内存大小 `InstanceMemorySize` 和根节点 `Root`
+
+通过 `UBehaviorTreeComponent::LoadedTemplates` 缓存加载过的 `UBehaviorTree` 资产信息,如果加载过直接从缓存中获取 `InstanceMemorySize` 和 `Root`
+
+如果没有加载过该 `UBehaviorTree` 资产,则开始加载
+
+首先通过 `InitializeNodeHelper` 来缓存所有节点信息
+
+```cpp
+TArray<FBehaviorTreeNodeInitializationData> InitList;
+uint16 ExecutionIndex = 0;
+InitializeNodeHelper(NULL, TemplateInfo.Template, 0, ExecutionIndex, InitList, Asset, this);
+```
+
+> `TemplateInfo.Template` 就是 **根节点** 的复制体
+
+然后计算每个节点占用的内存大小,计算并设置数据内存偏移
+
+```cpp
+for (int32 Index = 0; Index < InitList.Num(); Index++)
+{
+	InitList[Index].Node->InitializeNode(InitList[Index].ParentNode, InitList[Index].ExecutionIndex, InitList[Index].SpecialDataSize + MemoryOffset, InitList[Index].TreeDepth);
+	MemoryOffset += InitList[Index].DataSize;
+}
+```
+
+在运行时,会将每个节点的数据都保存在一个连续内存中,通过各自节点的 `MemoryOffset` 直接从连续内存中获取对应的数据
+
+#### InitializeNodeHelper
+
+虽然函数名字是 `InitializeNode`,其实是 复制 + 初始化,因为函数中充斥着 `StaticDuplicateObject`
+
+![](Image/001.png)
+
+首先,根节点一定是 `UBTCompositeNode`,从上图就可以看到 `Root` 下只能连接且只能连接一个 `UBTCompositeNode`
+
+> `Composite`: 组合,混合
+
+作为 `UBTCompositeNode` 自然保存着 **子节点** 和挂载在自己身上的 `Serve` 节点
+
+```cpp
+UCLASS(Abstract, MinimalAPI)
+class UBTCompositeNode : public UBTNode
+{
+	TArray<FBTCompositeChild> Children;
+	TArray<TObjectPtr<UBTService>> Services;
+	// some function else ...
+}
+
+struct FBTCompositeChild
+{
+	TObjectPtr<UBTCompositeNode> ChildComposite = nullptr;
+	TObjectPtr<UBTTaskNode> ChildTask = nullptr;
+	TArray<TObjectPtr<UBTDecorator>> Decorators;
+	TArray<FBTDecoratorLogic> DecoratorOps;
+};
+```
+
+> `FBTCompositeChild` 代表子节点,根据 `ChildComposite` 和 `ChildTask` 的属性是否有效来判断是 `CompositeNode` 还是 `TaskNode`
+
+![](Image/002.png)
+
+由于根节点是 `UBTCompositeNode`,它不能也不应该存在 `UBTDecorator`,所以在上图中,根节点的 `UBTDecorator` 是深蓝色的,表示无效
+
+回到 `InitializeNodeHelper` 函数中
+
+![](Image/003.png)
+
+