近学习了UE4官方文档的行为树快速入门指南,发现里面的部分逻辑稍稍有点混乱和重叠,于是加入了自己的想法,修改了部分行为树逻辑,优化了其AI寻路能力。
初始的基本操作和资源创建同官方文档一样:1个Follower_AI_CON即AI控制器,1个FollowerBT行为树,1个FollowBlackboard黑板,1个Character蓝图资源AI_Character。
打开FollowBlackboard黑板资源,创建1个TargetToFollow的Object变量,1个HomeLocation的Vector变量,1个TargetLocation的Vector变量,保存后退出。
打开Follower_AI_CON控制器,创建1个HomeLocation的Name变量,编写蓝图节点逻辑
添加EventBeginPlay事件,绑定黑板资源为FollowBlackboard,设置HomeLocation变量存储AI_Character的初始坐标(Target为黑板自身,KeyName为Name变量HomeLocation,VectorValue为AI控制器下Pawn的ActorLocation),之后运行行为树FollowerBT。
打开AI_Character蓝图,在Mesh中指定人物骨骼和角色动画蓝图,选中Components窗口的AI_Character(self),在Pawn选项中指定AIControllerClass为Follower_AI_CON,这样在创建AI_Character实例时,会自动创建1个AI控制器。
打开FollowerBT行为树,点击NewService,创建一个AgroCheck业务,前面的逻辑和官方文档一样,添加Branch节点判断AI控制器的引用AI_CON_Ref是否为空,空则将EventReceiveTick的OwnerActor输入参数强制转换成目标AI控制器后赋值给AI_CON_Ref。之后获取到场景中的所有AI_Character(在目标检测中作为忽略Actor目标,防止AI_Character互相检测导致混乱);获取到AI控制器下Pawn的ActorLocation作为目标检测的圆心(同时设置为MyLocation),Z轴添加15单位作为球体检测的半径终点,辐射半径设为1000作为目标检测的范围,检测的目标种类拖选成数组后设置为Pawn(即只会检测到类型为Pawn的目标)。
个人觉得接下来官网教程的蓝图逻辑有些不合适。官网上将目标检测的结果循环遍历,创建一个射线检测,MyLocation为起点,目标检测到的Actor为终点(即二次检测),别忘了Actor to Ignore连接到AI_Character。将射线检测的结果Actor和目标检测的结果Actor进行比较,结果作为Branch节点的判断依据,相同则将该Actor设为TargetToFollow,并将其Location设为TargetLocation;不相同则将TargetToFollow设为空值。
个人觉得不合理的地方如下:
1.对目标进行的二次检测重复多余,且没有意义,相当于将一个数组中的元素与数组中的所有元素进行比较(包括自身比较自身,且逻辑上两两比较了两遍),增加了逻辑复杂度和时间复杂度,导致的结果是之后的Branch节点频繁被调用,双分支(True,False)一直在重复执行;
2.并没有突出检测到的目标为正确寻路目标,而是使得所有在检测范围内的Pawn都符合寻路条件,AI_Character会将检测到的第一个Pawn作为跟踪对象;
3.目标监测范围内没有Pawn时,数组为空,导致之后的Branch节点不会执行。
所以我在官方文档的基础上加入了自己的想法,更改后的蓝图逻辑如下:
对目标检测的输出进行Branch判断,检测到Pawn目标时进行数组循环遍历,没有Pawn目标时直接对TargetToFollow赋值为空。对HitResult的Actor进行强制类型转换,转换成PlayerCharacter(玩家控制的角色),转换成功则表示玩家进入AI_Character的检测范围,并将玩家设置为TargetToFollow,玩家的Location设置为TargetLocation。
打开FollowerBT行为树,点击NewDecorator创建一个CloseEnough的Decorator,
将输入参数OwnerActor强制转换为Follower_AI_CON,赋值给AI_CON_Ref,连接到输出节点,添加1个Boolean输出参数,将TargetToFollow的Location减去AI控制器下Pawn的Location(即AI_Character和目标之间的距离)和预设距离进行比较,大于等于预测距离(即两者距离太远)则为True(继续执行Decorator下的逻辑),否则停止之后的逻辑。
打开FollowerBT行为树,点击NewTask,创建1个RapidMoveTo的任务,
首先进行AI_CON_Ref的非空判断,为空则将OwnerActor强制转换成Follower_AI_CON赋值给它,不为空则进行AIMoveTo,Pawn为AI控制器下的Pawn(即AI_Character),TargetActor为TargetToFollow。移动成功后结束此次行为树任务。
最终的行为树运行逻辑如下:
AgroCheck的刷新Tick为0.5s,TargetToFollow和TargetLocation分别对应于黑板资源的同名参数,之后进入分支判断,TargetToFollow非空则进入左侧,AI_Character和目标的距离大于100则进行RapidMoveTo任务;TargetToFollow为空则进入右侧分支,判断AI_Character是否位于TargetLocation,及TargetLocation是否为空,如果AI_Character已经到达TargetLocation则等待2.5s后返回HomeLocation。在这里我删除了移动到TargetLocation的任务,否则会造成AI_Character在TargetLocation和HomeLocation之间不间断的移动,删除之后AI_Character移动回HomeLocation之后保持静止,直到TargetToFollow的再次确立导致的左侧行为树分支开启。