UE代码-游戏AI-行为树执行流程(待更新)

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()
posted @ 2023-02-08 10:48  ccsu_madoka  阅读(314)  评论(0编辑  收藏  举报