1.项目设置
首先我们导入一个第三人称蓝图模板
在资源文件夹中找到ThirdPersonBP文件夹,右键单击,创建一个名为AI的文件夹
在 ThirdPersonBP > Blueprints 文件夹中,将 ThirdPersonCharacter 拖到 AI 文件夹上,然后选择复制到这里。
在AI文件夹中,创建一个基于AIController的蓝图类
将 AIController 蓝图命名为 Enemy_Controller,将 ThirdPersonCharacter 蓝图命名为 Enemy_Character
打开Enemy_Character,从蓝图中删除所有脚本
选择 CharacterMovement 组件,然后在 细节 面板中将 MaxWalkSpeed 设置为 120.0,这使得AI进行巡逻并未追逐玩家时,速度会降低。
选择类默认值,在细节面板中设置AI Controller Class设置为Enemy_Controller。
将Enemy_Character拖入关卡。
在左边放置面板中,将Nav Mesh Bounds Volume拖入关卡。
选中Nav Mesh Bounds Volume后,按下R缩放体积,让他覆盖整个关卡。按下P键可看他覆盖区域。
这一步将生成寻路网格体,是我们的AI角色可以在网格体中移动。(绿色区域表示可以导航的位置)。
2.黑板设置
在AI文件夹下单击右键,在 人工智能中选择Blackboard,将其命名为BB_Enemy。
在BB_Enemy黑板内,单击新键值按钮并选择Object。
将其命名为EnemyActor,并设置Actor为他的基类。
再新添一个新键,将其类型设为bool,并命名为HasLineOfSight。
再添加一个新键值,将其类型设置为Vector,并命名为PatrolLocation。这将记录到AI巡逻时移动到的位置。
3.行为树布局
在AI文件夹中单击右键,在人工智能选项中选择行为树。并将其命名为BT_Enemy。
打开BT_Enemy,在 细节 栏中将BB_Enemy指定为黑板资产。
在图表中,单击鼠标左键拖出根节点,然后添加一个Selector节点。
选择这个节点,在细节面板中将节点名称改为AI Root。
选择AI Root节点单击拖出一个Sequence节点,并命名为Chase Player。
此处使用了序列(Sequence)节点,因为我们打算告诉AI完成一系列动作:旋转朝向玩家,改变移动速度,然后移动并追逐玩家。
选择AI Root节点,单击拖出一个Sequence节点,命名为Patrol
再在AI Root节点拖出一个Wait任务节点。并将Wait Time设置为1.0.
注意每个节点上的数字:
行为树 会从左到右和自上而下执行,因此节点的排列很重要。对AI最重要的动作通常应该放在左边,而次要的动作(或退却行为)应该放在右边。子分支会以相同的方式执行,如果任何子分支失败,整个分支将会停止执行,导致失败并返回上级树。举例而言,如果 追逐玩家(Chase Player) 节点失败,它将返回至上级 AI根(AI Root),然后转变为 巡逻 (Patrol)节点。
从Chase Player节点中拖出Rotate to Face BBEntry任务节点,这个特殊的 任务 节点使你能够指定一个想要旋转并面向的 黑板条目,在本例中此条目是 Enemy Actor(玩家)。添加该节点后,你会在 细节(Details) 面板中看到 黑板键 将自动设为 EnemyActor,因为它过滤Actor的黑板变量,而且是列表中的第一个变量。如果需要调整成功条件范围并更改 节点名称(Node Name),可对 精度(Precision) 选项进行调整
在AI文件夹中将这个任务重命名为BTT_ChasePlayer。
回到BT_Enemy中,添加BTT_ChasePlayer任务,再在后面添加Move To。
和上面方法一样,再创建一个新 任务节点,并将其重命名为 BTT_FindRandomPatrol,然后将其连接到 Patrol 节点。再在后面添加Move To节点。点击Move To节点在细节面板将Blackboard Key设置为PatrolLocation。这将让AI移动至巡逻位置。
再Move To后面添加Wait节点,设置 Wait Time 为 4.0、Random Deviation 为 1.0。 这会指示AI在巡逻位置(PatrolLocation)等待3-5秒(随机偏差将在等待时间上+或-1秒)
4.任务设置–追逐玩家。
在 BTT_ChasePlayer 中点击右键并添加 事件Receive Execute AI 节点。
Controlled Pawn 引脚后连接 Cast to Enemy_Character 节点
在AI文件夹中,打开 Enemy_Character 蓝图,并添加一个名为 Update Walk Speed 的函数。
在 Update Walk Speed 函数的 细节 面板中,添加名为 NewWalkSpeed 的 浮点(float) 输入。
将 CharacterMovement 组件拖离"Component"选项卡,然后使用 设置最大Set Max Walk Speed 进行如下连接。
回到 BTT_ChasePlayer 任务节点内,从 As Enemy Character 节点调用 更Update Walk Speed 函数并设置为 500.0,然后按下图进行连接。
在 Update Walk Speed节点 之后,添加两个 Finish Execute 节点,并按下图进行连接。
我们成功将其投射到Enemy_Character后,我们在此将该任务标记为成功结束。如果被控制的Pawn不是Enemy_Character,我们需要处理这种情况,所以我们将任务标记为不成功,将任务中止。
右键单击 New Walk Speed 引脚,然后将其提升为变量,并命名为ChaseSpeed。
启用 ChaseSpeed 变量的 可编辑实例。这样做使我们可以从蓝图外部对其进行设置,并将该值作为 行为树 的内部属性进行调用。
5 - 任务设置 - 随机巡逻
在 BTT_FindRandomPatrol 中,使用 Event Receive Execute AI 和 Cast to Enemy_Character。在 As Enemy Character 之后调用 Update Walk Speed,并将 New Walk Speed 提升为一个变量,命名为 Patrol Speed,设置步骤如下:
点击编译,之后Patrol Speed变量的设置如下所示:
如果没出现Default Value选项记得先编译哦。
在 Controlled Pawn 之后连出引线,连接Get Actor Location,然后设置 GetRandomReachablePointInRadius,在他的返回函数(Return Value)后面加个分支。
将GetRandomReachablePointInRadius 上的 半径 (Radius)提升为变量并命名为PatrolRadius。变量的细节面板设置如下。
此处我们在AI角色当前位置的1000个单位内寻找一个随机位置。我们还要使用分支节点,处理无法找到要移动到的随机点这种极端情况。
在 Random Location 引脚后连出引线,使用 Set Blackboard Value as Vector,Key 提升为名为 PatrolLocation 的变量。变量的细节面板如下设置:
使用另一个 Set Blackboard Value as Vector 节点,设置该 Value 的来源为 Get Actor Location。
继续上一步,如下所示连接两个节点,Finish Execute 被标记为 Success。
如果敌人找到了一个要前往的随机位置,它将作为要前往的位置被存储在黑板中。如果找不到位置,它将使用当前位置,并在尝试新位置之前保持不动。我们还需要对受控Pawn不是Enemy_Character的极端情况进行处理。
从 Cast Failed 引脚连出引线,使用 Finish Execute节点,将 Success 禁用。
总体图如下:
6 - AI控制器设置
在 AI文件夹中打开 Enemy_Controller 蓝图,添加一个 Event On Possess 节点。
从 Event On Possess 连出引线,添加一个 Run Behavior Tree 节点,将其 BTAsset 设为 BT_Enemy。
在 Components 窗口中单击 +Add Component,搜索并添加 AIPerception Component。
在 AIPerception 的 细节 面板中,添加 AI Sight config,并启用 Detect Neutral。
在 AIPerception 细节面板的 Events 部分,点击 On Target Perception Updated 旁边的 + 符号。
在图表中 On Target Perception Updated 后连出引线,添加一个 Actor Has Tag 节点,将 Tag 设为 Player。
从 Stimulus 引脚,添加 Break AIStimulus 节点。
添加 分支 节点,将其 条件(Condition) 按照下图进行设置。
从该 分支 的 False(假) 连出引线,使用 Set Timer by Event,将其 Time 设为 4.0。
右键单击将 时间(Time) 提升为变量,并将其命名为 LineOfSightTimer
右键单击 Set Timer by Event 的 Return Value引脚,将其提升为名为 EnemyTimer 的变量。
这通过 句柄(Handle) 的方式保存对定时器(Timer)的引用。该句柄可以通过脚本调用,从而使自身无效,并清除任何相关事件(防止相关事件被执行)。我们可以在稍后当AI在Line of Sight Timer耗尽之前再次看到玩家时使用该节点,这可以防止AI让玩家离开视野并放弃追逐。
创建一个 自定义事件,并将其命名为 StartEnemyTimer,然后将其连接至 Set Timer by Event 的 Event 引脚。
单击右键,然后在 变量 > AI 下,添加一个 获取黑板(Get Blackboard) 节点。
在 黑板(Blackboard) 后连出引线,使用 Set Value as Bool 和 Set Value as Object,并按如下所示进行连接。
右键单击并将两个 键名(Key Name) 分别提升为名为 HasLineOfSight 和 EnemyActor 的 变量。
编译蓝图,并将两个 键名(Key Name) 的 默认值 分别设置为 HasLineOfSight 和 EnemyActor。
回到 分支 的 True(真),使用 Get EnemyTimer,然后使用 Clear and Invalidate Timer by Handle。
在 Set Value as Bool 节点上启用 Bool Value,并将 Actor 引脚拖至 Object Value,如图所示。
单击 编译(Compile) 进行编译,然后关闭蓝图。
7.最后的设置!
在 内容浏览器 中的 Content > ThirdPersonBP > Blueprints下,ThirdPersonCharacter 蓝图。
在 细节 面板中,查找并添加 tags,并设置为 Player。
打开 AI 文件夹中的 Enemy_Character 蓝图
在 细节 面板中查找 旋转(Rotation) 并启用 Use Controller Rotation Yaw。
开 BT_Enemy,右键单击 Chase Player,然后在 添加装饰器… 下选择 Blackboard。
选择所添加的 Blackboard Based Condition,并对 细节 面板进行以下设置。
点击 BTT_FindRandomPatrol 节点,在细节面板将Patrol Location设置为PatrolLocation。
编译 并关闭 行为树,然后在编辑器中 运行。
AI小人就会在地图中开始巡逻,看到你之后就会追着你跑啦~