摘记 – 《Unity3D人工智能编程精粹》

【适用 & 关键词】 Unity3D游戏开发爱好者、游戏AI、AI入门读物、数字媒体专业


【1.Unity3D人工智能架构模型】

1.对于游戏AI,可认为它们一直处于 感知 -> 思考 -> 行动的循环中。

2.在大部分现代游戏模型中,我们可以将AI任务划分为三个层级:运动层,决策层和战略层。

3.导航和寻路是运动层AI的主要任务。

4.决策层和战略层的功能可以利用有限状态机或行为树技术实现,也可以采取模糊状态机,神经网络等技术实现(但比较复杂)。

【2.实现AI角色的自主移动——操控性为】

1.操控行为需要的主要基类   

将AI角色抽象成一个质点——Vehicle类(包含位置,质量,速度,最大力,最高速度,朝向)。

Vehicle位置的计算方法如下:

①确定每一帧的当前操控力(最大不超过最大力)

②除以Vehicle的质量mass,可以确定一个加速度

③将这个加速度与原来的速度相加,得到新的速度(最大不超过最高速度)

④根据速度和这一帧流逝的时间,计算出位置的变化

⑤与原来的位置相加,得到Vehicle的新位置    

控制AI角色移动——AILocomotion类:它真正控制AI角色的移动,包括计算每次移动的距离,播放动画。 (theRigidbody.isKinematic 刚体是否遵循动力学原理,如果isKinematic启动,碰撞和关节将不会影响这个刚体,刚体将通过改变transform.position根据动画或脚本控制)    

各种操控性为的基类——Steering类:是所有操控性为的基类,包含操控性为共有的变量和方法,控制AI角色的寻找,逃跑,追逐,躲避,徘徊,分离,队列,聚集等

2.个体行为   

靠近行为:首先需要计算出AI角色在理想情况下到达目标的预期速度(可看作是AI角色当前位置到目标位置的向量),操控向量是预期速度与AI角色当前速度的差,该向量大小随着当前位置的变化而变化。 当它到达目标后,由于惯性的存在,会穿过目标、转向、再次接近目标,如此往复。    

离开行为:离开和靠近相反,只要将预期速度取相反方向即可。 (采用Vector3.sqrMagnitude函数比Vector3.Distance函数计算距离的速度更快)    

抵达行为:在角色距离目标较远时,抵达与靠近行为的状态是一样的,但是接近目标时,开始减速,最终恰好停在目标位置。何时开始减速通过参数进行设置,这个参数可以看成是停止半径。当角色在停止半径之外,以最大速度移动;当角色进入停止半径之内时,逐渐减小预期速度,直到减小为0。这个参数的设置很关键,它决定了抵达行为的最终效果。    

追逐行为:(智能追逐行为)使用一个简单的预测器,在每一帧重新计算它的值。假设采用一个线性预测器,又假设在预测间隔T时间内角色不会转向,角色经过时间T之后的未来位置可以用当前速度乘以T来确定,然后把得到的值加到角色的当前位置上,就可以得到预测位置了。最后再用预测位置作为目标,应用靠近行为即可。(关于预测间隔T,可以把它设为一个常数,也可以当追逐者距离目标较远时设为较大的值,而接近目标时设为较小的值。)    

逃避行为:与追逐相反,使AI角色逃离预测位置。    

随机徘徊行为:工作原理同内燃机的气缸曲轴传动相似,在角色(气缸)通过连杆联结到曲轴上,目标被限定曲轴圆周上,利用靠近行为移动目标。为了看得更似随机徘徊,每帧给目标附加了一个随机的位移,这样,目标便会沿着圆周不停的移动。将目标限制在这个圆周上,是为了对角色进行限制,使之不至于突然改变路线。(感觉和随机给个方向一样)。    

路径跟随行为:最简单的跟随路径方式是将当前路点设置为路点列表中的第一个路点,用靠近行为产生操控力来靠近这个路点,直到非常接近这个点(需要设置一个路点半径,当AI角色进入路点半径范围内认为它已经到达当前路点);然后寻找下一个路点,设置为当前路点并接近它。最后再根据需要决定是回到第一个路点还是停在最后一个路点上。    

避开障碍行为:发现障碍,确认是否碰撞,若碰撞给予推开的操控力。

3.群体行为   

分离:首先搜索指定领域内的其他邻居,对每个邻居,计算AI角色到该邻居的向量r,将向量r归一化,得到排斥力方向,由于排斥力的大小是与距离成反比的,因此还需要除以|r|,得到该邻居对它的排斥力,然后把所有邻居的排斥力相加,就得到了分离行为的总操控力。    

队列:通过迭代所有邻居,可以求出AI角色朝向向量的平均值以及速度向量的平均值,得到想要的朝向,然后减去AI角色的当前朝向,既可以得到队列操控力。    

聚集:迭代所有邻居求出AI角色位置的平均值,然后利用靠近行为,将这个平均值作为目标点。

4.操控行为的快速实现——Unity3D开源库UnitySteer

【3.寻找最短路径并避开障碍物——A*寻路】

1.A*寻路的几个相关术语介绍: 地图:“地图”是一个空间,也可以称为“图”,它定义了场景中相互连接的可行走区域,形成一个可行走网络,A*在这个空间内寻找两个点之间的路径。 目标估计:是指在寻路过程中估算代价的方法。 代价:在寻路过程中,有许多影响因素,例如时间、能量、金钱、地形、距离等。 节点:节点与地图上的位置想对应,可以用它来记录搜索进度。 导航图:要进行寻路,首先需要将游戏环境用一个图表示出来,这个图就称为导航图。导航图可以有多种形式,介绍其中最重要的三种:基于单元的导航图,可视点导航图和导航网格。

2.基于单元的导航图:这种表示方式最容易理解和使用,而且由于它的结构很规则,因此易于动态更新,如动态增加建筑物或其他障碍等;但如果游戏环境中包含多种不同的地形或是RTS游戏,那么占用的内存空间和消耗的CPU资源将会很大。

3.可视点导航图:最大优点是它的灵活性。分散在各处的路径点是由场景设计者精心选择的,能覆盖绝大部分可行走的区域,还可以将其他一些重要位置的点包含进去,同时增加响应的信息存储;缺点:当场景很大时,手工放置路径点是很繁琐的工作,也很容易出错。其次,它只是一些点和线段的集合,无法表示出实际的二维可行走区域,角色只能沿着那些边运动。它还存在严重的组合爆炸问题。

4.导航网格:将游戏场景中的可行走区域划分成凸多边形。与前两种导航图相比,导航网格的优点是可以进行精确的点到点移动。高效,占用的内存较小,搜索路径的速度也会有很大的提高。另外,由于游戏场景本身就是由多边形构成的,因此,通过事先设计好的算法就能够自动地将可行走区域划分成多边形,生成导航网格,而不需要人工干预;缺点:生成导航网格需要较长的时间,因此,在地形经常发生动态变化的场景中很少使用,多用于静态场景中。 (A* Pathfingding Project插件中,为了更快的在游戏过程中生成动态导航网格,采用了Navmesh cutting技术,主要思想是在原始的导航网格图中挖洞,从而为新增加的障碍物腾出空间,然后对香瓜你的三角形稍做修补。但是只能动态增加障碍物,不能动态移除障碍物)。

5.A*寻路算法是如何工作的 (假设寻路是基于单元的导航图的,用每个格子的中心点来表示寻路节点,每个格子周围的8个相邻格子表示节点之间的可行走连接) 在A*算法中,使用了两个状态表,Open表和Closed表。Open表由待考查的节点组成,Closed表由已经考查过的节点(如果一个节点的所有相邻节点都被计算了f,g,h值且被放入Open表中以待考查,那么他就是已考查过的节点)组成。 开始时,Closed表为空,而Open表仅包括起始节点。每次迭代中,A*算法将Open表中具有最小代价值(f值最小)的节点取出进行检查,如果这个节点不是目标节点,那么考虑该节点的所有8个相邻节点。对于每个相邻节点按下列规则处理: ①如果它既不在Open表中,也不在Closed表中,则将它加入Open表中; ②如果它已经在Open表中,并且新的路径具有更低的代价值,则更新它的信息; ③如果它已经在Closed表中,那么检查新的路径是否具有更低的代价值。如果是,那么将它从Closed表中移出,加入到Open表中,否则忽略。 重复上述步骤,直到到达目标节点。如果在到达目标之前,Open表就已经变空,便以为着在起始位置和目标位置之间没有可达的路径。

6.checked和unchecked:checked和unchecked关键字用来限定检查或者不检查数字运算溢出的。 checked:数学运算溢出时会抛出overflowException unchecked:不会检查溢出

7.RTS的小队寻路–用操控行为和A* 寻路实现 P120-137

8.使用A* Pathfinding Project插件需要注意的问题

①A* Pathfinding Project插件实现了二维情况下的寻路(平面或二维曲面),但是由于开销巨大,无法实现真正的三维空间中的快速寻路。

②A* 寻路一般用于已知目标位置的点到点的寻路。如果实现并不知道目标位置,或者目标位置有多种可能性,就必须对每种可能性应用A* 算法,这样会带来非常大的开销。在这种情况下一般采用Dijkstar算法。

【4.AI角色对游戏世界的感知】

1.在游戏中,AI角色可以通过两种方式获得游戏世界的信息–轮询和事件驱动。简略地说,轮询是通过积极地观察世界的方式来获得信息,事件驱动是通过坐等消息的方式来获得信息。

2.

触发器:Trigger类中包含所有触发器共有的相关信息和方法。    

感知器:Sensor类是所有感知器的基类,可派生视觉感知器和听觉感知器。 (触发器和感知器都保存了事件管理器)    

事件管理器:这个类负责管理触发器的集合。它维护一个当前所有触发器的列表,当每个触发器被创建时,都回向这个管理器注册自身,加入到这个列表中。事件管理器负责更新和处理所有的触发器,并且触发器已过期需要被移除时,从列表中删除它们。事件管理器还维护了一个感知器列表,向这个管理器注册,加入到感知器列表中。

3.记忆感知:为了让角色具有记忆,实现了一个SenseMemory类,这个类具有一个记忆列表,列表中保存了每个最近感知到的对象、感知类型、最后感知到该对象的时间以及还能在记忆中保留的时间,当有一段时间没有感知到这个对象,这个时间超出了记忆时长时,就会将这个对象从记忆列表中删除。

4.AI士兵的综合感知示例P164-182

【5.AI角色自主决策–有限状态机】

1.有限状态机(Finite State Machine)由一组状态、输入和根据输入及现有状态转换为下一个状态的转换函数组成。

2.用Switch语句实现有限状态机: FSM基类,含3个虚函数,Initialize(),FSMUpdate(),FSMFixedUpdate(). SimpleFSM继承FSM,含4个状态(巡逻,追逐,攻击,死亡),FSMUpdate()里根据当前状态切换对应的不同状态函数

3.FSM框架实现通用的有限状态机: FSMState是所有状态类的基类。状态类中具有添加转换,删除转化的方法,用于管理记录这些转换。另外这个类中还包括Reason和Act方法,Reason方法用于确定是否需要转换到其他状态,应该发生哪个转换,Act方法定义了在本状态的角色行为。 AdvancedFSM类是FSM类的派生类,负责管理FSMState的派生类,并且随着当前状态和输入,进行状态更新。 AIController是AdvancedFSM的派生类,负责创建有限状态机,通过它来控制AI角色。FSMFixedUpdate()里调用当前状态的Reason方法,确定当前发生的状态;调用Act方法执行行为。

【6.AI角色的复杂决策–行为树】

1.行为树主要采用4中节点来描述行为逻辑,分别是顺序节点,选择节点,条件节点和行为节点。每一颗行为树表示一个AI逻辑。要执行这个AI逻辑,需要从根节点开始遍历执行整棵树。遍历执行的过程中,父节点会根据自身的类别,确定需要如何执行、执行哪些子节点并继而执行,子节点执行完毕后,会将执行结果返回给父节点。 节点从结构上分为两类:组合节点、叶节点。叶节点包含条件节点和行为节点。树的中间节点由组合节点组成,组合节点用来控制树的便利方式,最常用的组合几点有选择节点,顺序节点,并行节点,修饰节点等。

2.权衡行为树和有限状态机: 本质上来说,状态机是事件驱动的。状态机既可以采用轮询的方式实现,也可以采用事件驱动的方式实现。大多数行为树都是自顶向下,采用轮询的方式实现的。

3.React插件快速创建敌人AI士兵行为树

———- Done ———-

嗯 总的来说 这本书非常的入门 对游戏AI感兴趣的看看不错

Add a Comment

您的电子邮箱地址不会被公开。 必填项已用*标注