1,处理黑板
UseBlackboard()(当行为树资源有黑板,并且当前控制器没有黑板或者两个黑板不一样时执行)
2,加载并发起行为树
1,若未初始化行为树组件,新建行为树组件对象
2,BTComp->StartTree()
1,找到树的根节点
2,若行为树已执行并且根节点相同直接返回(所以同一个角色运行两次相同的行为树,他并不会中断当前行为并重新执行任务)
3,StopTree()
4,初始化新的行为树:ProcessPendingInitialize()
1,清除所有实例
2,获取行为树管理器,并添加活跃组件
(BehaviorTreeManager的主要作用就是处理行为树的资源)
(这个活跃组件数组看起来没怎么用到,组件的Tick走的也不是这里,可能是给开发者用的?)
3,新增实例:PushInstance()
1,检查是否可以加载行为树:
1,检查黑板:如果黑板不一致,则不能使用这颗行为树
2,检查能不能获取BTManager
(行为树管理器)
3,如果是运行子行为树,检查能不能执行这棵子树
(调用CanPushSubtree()判断,平行节点的CanPushSubtree返回为false,所以平行节点下面不能Runbehavior)
2,加载树:BTManager->LoadTree()
1,处理每个节点的信息:InitializeNodeHelper()
1,父节点
2,执行顺序
3,内存大小
2,将信息保存在LoadedTemplates中
3,初始化BehaviorTreeInstance与BehaiorTreeInstanceId(看着似乎可以用KnownInstances找到的实例Id)
(BehaiorTreeInstanceId保存了行为树的各种公共信息,也可以通过这些信息来确定一颗行为树,区分BehaviorTreeInstance。)
(BehaiorTreeInstanceId同时预留了部分空间,用于保存执行行为树时的状态等信息用于回滚数据。)
1,实例是直接new了一个对象
2,实例Id:UpdateInstanceId
(用KnownInstances去重,没有则新增一个BehaiorTreeInstanceId)
4,将创建好的实例BehaviorTreeInstance推入InstanceStack中(可用InstanceStack找到所有实例)
5,发起请求:RequestExecution()
执行新的任务并在最后ScheduleExecutionUpdate():ScheduleNextTick()
3,更新行为树,查找下一个任务节点
1,tickComponent
(TicmComponent每帧都会执行,但执行请求还需要NextTickDeltaTime小于0,上面的ScheduleNextTick就是将NextTickDeltaTime设为了0)
(值得注意的是,AccumulatedTickDeltaTime记录了距离上次执行逻辑,空跑TicmComponent的时间之和)
1,如果需要更新,就执行请求(搜索合适的任务):processExecutionRequest()
1,搜索前的准备
1,备份数据
(在之前加载行为树时记录了当时的BehaiorTreeInstanceId就是用于这里备份的)
SearchData.RollbackInstanceIdx = ActiveInstanceIdx;//这里记住了BehaiorTreeInstanceId的索引
SearchData.RollbackDeactivatedBranchStart = SearchData.DeactivatedBranchStart;
SearchData.RollbackDeactivatedBranchEnd = SearchData.DeactivatedBranchEnd;
CopyInstanceMemoryToPersistent()//将当前数据拷贝到BehaiorTreeInstanceId
(这个函数里正是使用KnownInstances获取的实例Id的引用)
2,收集需停用所有Service和Decorator:DeactivateUpTo()
从当前执行的节点向根节点回溯,并执行:OnChildDeactivation()
(也就是把自底向上把所有的Service和Decorator全给关了)
1,将节点(包括任务节点,复合节点)的服务节点加入SearchData
2,搜索
1,设置搜索范围
SearchData.SearchStart = ExecutionRequest.SearchStart;
SearchData.SearchEnd = ExecutionRequest.SearchEnd;
2,寻找下一个任务节点(行为树中搜索下一个合法任务的过程)
第一层while循环:枚举当前点
执行FindChildToExecute()查找当前点的子节点是否合法
第二层while循环:遍历子节点
检查是否通过子节点装饰器
其中一个通过检查返回成功
如果查找成功:
如果是Task就找成功了
如果是Composite,将合法子节点设为下一个当前点继续找
如果查找失败:
向父亲节点回溯
3,搜索后的检验与处理
1,搜索失败:
RollbackSearchChanges()//回滚数据
2,搜索成功:
1,中止当前任务:AbortCurrentTask()
2,记入新找到的Task
3,处理新的行为树逻辑:ProcessPendingExecution()