AI 状态机机制(虚幻三的做法)
1.Nav Mesh Bounds Volume (Navigate导航,操纵)指的是可以导航(操作)的区域。
2.MVC的编程模式:(Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。
通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。
通常视图是依据模型数据创建的。
Controller(控制器)是应用程序中处理用户交互的部分。
通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC 分层有助于管理复杂的应用程序,因为您可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。
MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。
)
3.创建一个Character命名为Enemy,将Mesh导入并添加至Character。调整位置和角度。
4.根据MVC思想,现在要创建一个Controller来写入处理程序,当然,程序中的需要的数据还是要来自于View中,也就是Character的蓝图中。这里为了方便就创建一个专门用于控制AI的控制器,AIController(BlueprintsClass)是Controller的子类。
5.接下来就要将控制器付给Character了,在self中找到Pawn中选择AI Controller Class更改为刚刚创建的Aicontroller.
6.要对AIController写入逻辑了,这里设想一下分别有四种状态,Patrol(巡逻),Chase(追捕),Attack(攻击),Back(返回)。因为都是状态,所以可以考虑将其写成枚举,通过SwitchOn来执行事件。
7.在Controller中创建一个枚举变量,类型就是刚创建的枚举,直接通过SwitchOn来控制函数,将每一种状态都写成一种函数,(这是大体的架构,内容一步一步写)。默认是先进行第一个状态(Patrol)通过改变枚举来进行状态的切换。(重点借鉴学习)
8.先进行Patrol的编辑,巡逻要以某一点为中心随机改变方向运动,在AI中一般用到的移动节点有三个(通过输入Move To都可以找到)各有不同第一个,是向着一个Actor移动,可以在Chase(追踪)的时候使用,第二个向着一个位置运动,可以在Patrol(巡逻)的时候用,第三个一般在比较复杂的情况使用,但是Actor的优先级高于Location.
9.在Patrol中使用Simple move to location,接着确定移向的点,在AI中的Navigation中有Get Random Point in Navigatable Radius.这里就要输入数据了,根据MVC编程模式,将数据放在V中。
10.在初始化的问题上,EventBeginPlay一般要用Character中的,比较稳定,以为Controller有时会在顺序上跟Character不同,所以一致放在Character中。
11.设置好需要考虑的数据,例如移动速度,巡逻时间之类的。
12.完成基本的巡逻之后就要考虑发现敌人(Player)之后的Chase(追踪)了。
13.追踪的思路是在一定范围内检测到Player靠近,之后想Player移动。移动好解决,利用Simple Move To Actor就可以解决,那么难点就是如何让检测Player的靠近,方法有很多,例如可以用Get Distance To获得两个物体之间的距离,通过距离来判断Player的靠近。根据项目的需要也可以有Find Look at Rotation,当两者的角度小于多少时完成判断,还有就是Get Dot Product To(暂时不知如何用),还可以用射线来做,用一个球形射线,Sphere Trace For Object.
14.这里用一种比较常用的方法,PawnSensing(角色检测),跟射线差不多,调整数据达到要求。在Controller中添加PawnSeneing调整好数据后,右击创建事件驱动,OnSeePawn,并将检测到的Pawn升级为一个变量,以供后面使用。
15.在Patrol中引出另一个分支,检测到目标的时候就要切换状态至Chase(追踪)。
16.在Chase中最基本的是跟随着Player移动,simple move to Actor
17.那么分析一下在 Chase中会发生什么情况,一种是,因为速度的原因没有追上,那么就要回去继续巡逻了(Back),一种是追上了,那么要进行Attack。
18.先分析没追上回去巡逻了,这里需要一个距离数值,当两者距离大于这个值时就要进入Back状态,回去继续巡逻。通过GetDistanceTo来获得两者之间的距离,与距离数值相比较,大于则进入Back状态。
19接着分析追上了进入Attack状态,这里需要一个攻击距离,当两者之间的距离小于攻击距离时,进入Attack状态。
20.接着编辑Back状态,在Back状态中,基本功能是Enemy回到原地继续巡逻,所以继续SimpleMoveToLocation,目标就是HomeLocation,此时判断,是否回到HomeLocation,回到则切换回巡逻状态,但是经过验证之间是有误差的,所以说,要判断当前的位置和Homelocation的距离(向量相减之后获得Length)小于50(自定义,合理即可)时,进入巡逻状态。
这里有一点需要特别注意,当返回巡逻状态后,进入巡逻,但此时巡逻状态有个判定:当检测到有Player接近时将Pawn付给CurrentPawn,当CurrentPawn有效时,则进入Chase状态,所以当Enemy回去巡逻时,应该将CurrentPawn清空,不能让其进入Chase模式。
21.接下来就要进行Attack状态的操作了,首先准备好动画,这里实际是思路跟上面差不多,有一点注意的是Attack的动画跟Walk的动画之间的切换,通过布尔值切换,这个布尔值要设在Enemy中,方便Controller和动画蓝图调用,进入Attack状态下将布尔值设为真,此时也就满足了由walk动画进入Attack的条件,并在状态下检测两者距离,如果脱离攻击范围,那么进去Back状态。从Attack动画中回到Walk的条件是布尔值为假,这个要在动画结束时添加一个事件,由这个事件去设置布尔值为假。
22.结束之后基本功能都实现了,下面进行优化,
1.会发现,在进行Attack动画时两者距离发生改变就会出现滑动的情况,这里解决办法各有千秋,可以在此动画状态下将移动速度设为0,动画结束后再设回来,这样显得就麻烦了许多,可以这么想,在进行这个击打动画时使整个Ai都不起作用,也就不会移动了,动画结束时再起作用,这里就要用一个布尔值来控制开关了,当然,开关要设在最初始的驱动上(EventTick),控制布尔值就要跟控制动画的布尔值同步了,进入Attack状态时将布尔值设为真,在动画结束的事件中江布尔值设为假。(这里还有一个BUG有待解决,就是这样的话Attack就会进行两次,产生的原因是,当进入Attack状态时,就要关闭AI,这会使得不能及时反馈位置信息进入巡逻模式,只能在动画结束后开启AI才能获得位置信息,然而此时也会再次进入动画)解决:既然是出现在执行动画的过程中进入了另一种状态,那么只需要在进入状态是检测动画有没有结束就OK了,在动画的末尾添加一个事件触发一个布尔值,在进入状态时检测一下布尔值就可以了,不需要完全关闭AI的。
2.CD问题,将两次击打之间设有一定的CD。这里需要注意的是在CD过程中,两者距离发生改变,那么就要直接跳转到巡逻状态。(避免CD过程中改变了距离,不进入动画也不切换状态)
3.速度的问题。(通过倍数改变)
4.还有一个数据结构的问题(table)
数据结构,
每一种不同的怪物将会有不同的所需要的数据,而这些数据虽然数值不同但是,类型都相同,那么就会用到DataTable,在建立DataTable之前要先建立一个结构体,将需要输入的变量全部输入,在Miscellaneous中创建一个DataTable。选择刚刚创建的结构体,添加元素,输入各项值,然后在目标初始化的过程中添加此数据,GetDataTableRow,(还有个GetDataTableRowName是获得名字的),将OutRow Break后将数据一一付给变量。
在工作中,一般会将CSV格式的表格写好数据之后导入UE,格式就是DataTable。