想要做一个AI随机漫游,有两种方法,一种是直接在AI角色蓝图中写,一种是使用行为树来移动。
用角色蓝图非常简单,但如果AI有复杂的行为,那么就需要使用行为树。
下面介绍两种方法如何使用。
角色蓝图是具体的动作逻辑。
控制器通过角色蓝图控制AI移动。
寻路网格体提供移动的场景。
不管使用哪种方法,都要先建立一个AI的角色蓝图。
可以直接复制一个第三人称角色蓝图,这样比较快速。
简单介绍一下蓝图的各组件作用:
b.删除一些与输入有关的变量:“基础转动速率”、“基础俯仰速率”
c.删除摄像机组件:camera Boom(摄像机升降臂)、跟随相机
需要给AI蓝图绑定控制器,不然AI无法移动。
a.添加AI控制器 - 替换刚刚删除的玩家控制器的功能
b.建立AI控制器蓝图
c.打开AI_ThirdPersonCharacter蓝图——PAWN——AI控制器类——绑定AI控制器蓝图
UE5这个界面里没有,可以在蓝图编辑器的细节面板中找到。
没有寻路网格体,AI也无法移动。
a.添加寻路网格体
模式 - 寻路网格体(Nav Mesh Bounds Volume)拖入场景
“细节”面板调整笔刷尺寸。
让网格体覆盖AI需要行走的场景。
寻路网格体大小不需要特别准确。
b.显示网格体
视口选项 - 显示 - 导航(快捷键P)
原理:游戏开始后,产生一个计时器,并开始漫游事件——AI获得一个随机点,通过控制器移动到这个点——计时器开始计时,1.5s后AI前往下一个点——循环
给角色蓝图新建一个自定义事件,包含随机漫游逻辑 - 增加一个函数,在游戏中反复调用自定义事件。
打开AI角色蓝图 - 在“事件图表”窗口右键创建“自定义事件custom event”,命名为“random wander随机漫游”。
“随机漫游”后跟“到Location的简单移动Simple Move To Location”函数。
“Get controller获取控制器”函数返回值与“到Location的简单移动”的controller参数连接。
“获取半径内能到达的随机点”起点为当前AI的位置:“获取Actor位置”函数的返回值连接origin (起点)
调整半径为1000。(看个人需求)
返回值与“到Actor的简单移动”的Goal参数连接。
创建“begin play”事件 - 连到“set timer by event以事件设置定时器”函数 。
random wander随机漫游事件连到“以事件设置定时器”函数的event引脚,设置开始时间time,勾选looping循环。
行为树一共有三个元素:
原理:1个行为会有2-3个动作,1个任务蓝图便是1个动作,黑板将任务蓝图的数值传递给行为树,行为树根据任务蓝图和黑板值控制AI的行为。
在内容栏里创建一个文件夹“BT_Assets”。
在文件夹中右键AI栏中创建一个行为树“BT_EnemyAI”,再创建一个黑板“BB_EnemyAI”。
打开AI控制器蓝图。
创建“Event On Posses事件控制时”事件。(AI被控制器控制时启动,其实就是开始游戏时启动)
拖拽执行引脚创建“Run Behavior Tree运行行为树”函数,在BTAsset下拉栏中选择BT_EnemyAI行为树。
在黑板创建一个向量变量来保存目标位置,作为新的漫游目的地
在行为树窗口切换为黑板。
在黑板选项卡新建一个“向量Vector”条目,命名为Target Location。
a.在行为树中新建任务BTTask_BluePrintBase,改名为“BTT_FindNavigatableLocation”。
新建文件夹来储存行为树任务,并打开任务蓝图 。
b.跟角色蓝图中的逻辑一样:
新建“Receive Execute AI事件接收执行AI” - 新建“获取可导航半径内的随机点Get random reachable point in radius”函数 ,半径改为1000 - “事件接受执行AI”事件的Controlled pawn引脚拖拽新建“获取actor位置”函数 - 获取actor位置的返回值与获取可导航半径内的随机点函数的Origin相连接。
c.处理随机参数的返回值
和之前的逻辑不同,一旦这个任务完成,它所包含的信息都会销毁。所以要把任务传给行为树,再传给黑板。
拖拽获取可导航半径内的随机点的random location新建“Set blackboard value as vector把黑板值设为向量”函数。 - 拖拽Key引脚并“提升为变量”,改名为Target Location Key。
并在我的面板中保证其为公开:因为要在行为树中操作。(名字要与黑板中的键相同,否则无法传递数值)
事件接受执行AI事件的执行引脚与将黑板值设为向量的执行引脚相连。
d.告诉行为树任务已完成
如果不告诉,任务会一直卡在这里。
将黑板值设为向量的执行引脚与“finish execut完成执行”函数的执行引脚相连 - 获取可导航半径内的随机点的返回值与完成执行的success引脚相连。
只要AI找到随机点,就判断成功。
AI行动顺序如下:
a.从根拖拽并添加一个sequence序列合成器
b.再添加一个sequnce合成,在细节面板改名为“随机漫游”
c.在sequence下从左到右添加之前创建过的任务、move to任务、wait任务。
d.BTT_FindNavigatableLocation并改名为“找到合适位置”,Target Location Key选取黑板键Target Location
e.Move To更改黑板键为Target Location
现在替换AI模型。类型最好是Character而不是Actor,这样才能调用pawn。
如果没有编写蓝图,可以将模型蓝图直接拖入场景,boss就被导入了。
如果已经编写好了角色蓝图,则在细节面板的网格体处替换MESH。
还要在动画类选取动画序列。
编写好boss蓝图后,发现boss在移动时在平移,而不是播放跑步动画。
a.找到BOSS动画蓝图。
b.找到Set is Accelerating一栏。
当前是获取的玩家的加速度,转换成向量,再转成长度。大于0则表示在加速。
但是我们的boss是个AI,并没有输入,所以需要获取当前AI的速度:
打断向量长度与0的判断。
在左边变量找到speed,按住ctrl拖入。
speed与0的判断相连。
再次运行游戏,boss移动时就会播放跑步动画了。
AI需要信息和数据才能在场景中移动并躲避障碍。
在场景中寻路是AI的基本功能,不仅仅是从A-B点。
寻路网格体都是预先计算(“烘焙”)好的,这意味着在游戏开始前,以2D网格体形式表示的寻路网格体就已经包含了场景对象和AI自身生成的碰撞数据。这就使得寻路的开销更低。对于那些代理数量或类型不确定的实时体验来说,这点尤为明显。
寻路网格体开销低、速度快、高可靠,可以快速实现导航功能,但是场景无法动态修改寻路网格体。
自动更新改为手动更新。
a.默认网格体自动更新 - 移动场景物件,寻路网格体会实时更新。(若关卡较大,会很耗性能)
b.(仅对较大关卡)关闭自动更新 - 编辑器偏好设置 - 关卡编辑器 - 杂项 - 关闭自动更新导航
c. 手动更新 - 构建 - 导航 - 构建路径(无需在意日志里的错误消息)
有时候我们需要一些高度或者障碍,这时候需要对寻路网格体进行一些属性上的调整,以应对复杂的需求。
创建寻路网格体时,Recast寻路网格体自动创建。
选中RecastNavMesh,在细节面板调整
如果想要尺寸更大、游泳、飞行的角色,只需要定义新的寻路网格体代理,并进行相应设置以适应新的尺寸和运动形式。
Gameplay调试器可以用来检测配置是否达到我们的要求,还可以用来检查问题出在哪一步。
游戏运行后,按“ ’ ”打开控制台。
以最快最有效的方式跟踪行为树的执行流程。
**a.**调试行为树信息
把玩家放在AI看不到的地方。
运行游戏。
打开行为树,选取AIC_ThirdPersonCharacter。
选取随机漫游的wait,F9打上断点。
也可以用返回执行上一个节点。
随着行为树越复杂,这个功能越好用。
b.使用Gameplay观察行为树
如果出包,或者屏幕有限,可使用Gameplay调试器。
运行游戏。
打开gameplay调试器。
按1隐藏AI信息,只显示行为树信息。
暂停游戏可观察具体流程信息、黑板信息。
AI最重要的环节 - 行为树。
借助行为树,可以轻松控制并显示AI的决策制定过程。
行为树的一种节点,下面无法添加其他节点。
是行为树分支的终点(但不是行为树的终点!)。
也被成为“叶节点”
合成是AI执行分支的根。不会像叶节点那样执行,但能创建一个结构,并根据其子节点的成败控制顺序。
任务和合成可以创建出各种方法来处理AI的行为。
不必纠结如何完成任务,只需制定决策完成任务即可。