之前两篇▶A*寻路——基础入门与战术寻路、▶A*寻路——跨层寻路和大家分享了一些A*的简单的用法和例子,这次分享下A*的多人寻路的做法,也算是A*的完结篇。
在我们玩魔兽或者红警的时候,我们经常会做的一个动作就是拖动大量人物,然后进行一些移动操作,这时被我们选中的人物会排好队依次前进,到达我们指定的地方。我们作为一个游戏设计者需要控制组成小队的多个AI角色,那么现在我们看看A*能做成什么样的效果。
首先我们从性能上分析,A*寻路要求的计算量是比较大的,很难在一帧之内完成,如果还是同时为一群AI寻路,A*寻路就会显得比较吃力了。
对于这样的情况,一种可能的解决办法是将A*寻路和之前说的群体操控行为结合,选择一个AI作为领队,用A*寻路算法为这个单元计算路径,然后队伍其他单位只要利用跟随领队行为,以及分离,聚集,队列和避障这几个组行为结合就可以了,这样不仅降低了寻路的计算量,而且群体看起来比较真实,也不会互相拥挤碰撞。
但是如果小队的规模比较大,或者地形很复杂,有好几层的话,这个解决方案不一定能正常工作,这时我们可以采用另外一个方法,就是为每个单元的目标位置都加上一个偏移量,这样我们的小队单元接近目标的时候,就不会互相拥挤或者碰撞,好,那我们开始!
我们分析好思路,那现在我们就从以下几个方面开始考虑
集群系统:小队的每个单元需要协同移动,所以我们要编写让他们以这种方式移动的逻辑
雷达: 用来寻找周围的队友,如果距离过近就产生一个排斥力。
寻路与避开障碍:让那个单元找到一条路径,而且需要避开中途的障碍物。
目标点:如果全部单元的目标点都是同一就会产生堆叠和碰撞,所以我们需要为小队的每个单元生成不同的目标点,这样就不会互相堆叠起来。
首先新建个场景,添加Obstacles,Ground层。然后创建一个平面将Layer设置为Ground。然后添加一些墙体做障碍物,将Layer设置为Obstacles。
然后创建一个空物体命名为A*,选择GridGraph,设置好相应参数,扫描,建立基于单元的导航图。最后创建一个目标点预制体,创建一个空物体,命名为MyDestination,添加rigidbody,然后添加一个Destination.cs脚本,这个预设物就作为我们双击鼠标在目标点后产生的AI移动的目标点。
然后放到Project目录,后期自动产生。
然后,我们设定一个目标点,当我们双击鼠标,就在鼠标点的地方产生一个目标点,如果我们小队中全部成员都向这个目标点移动的话,那就会产生拥挤火堆叠,所以我们改成以原目标点为中心,为小队中每个成员寻找原目标点周围的位置作为寻路目标,我们来开始新建一个脚本Destination.cs 用来实现给目标点周围添加角色移动的点。
我们创建一个空物体,命名为myDestination ,把脚本拖上去,然后放到Project面板保存起来,下一步在创建一个目标位置管理器,创建一个空物体,名称为Manager,再添加一个DestinationManager.cs 脚本。
然后我们把刚才创建的myDestinationPrefab 拖到Manager的DestinationPrefab位置中,然后我们把人物拖入场景,命名为EnemyAI ,加入CharacterController角色控制器组件,调整好位置,在添加Seeker组件 Component-Pathfinding-Seeker , 再添加Boid脚本,为了能平滑移动,在单击component-Pathfinding-Modifiers-SimpleSmoothModifier 加入一个平滑脚本,设置好AI后,我们复制多几个出来,让他们组成角色小队。
我们需要实现群体中个体之间的协调运动,至少需要两种行为:聚集(用于产生将单元聚集一起的力)和分离(用于产生单元之间彼此分离的力),使他们不至于撞到一起。
然后我们还需要一个状态奇,为小队单元设置3种运动状态,Idle闲置,Moving移动和Organizing组织。
在Boid.cs脚本中,实现了"邻居检测雷达",使每个单元都可以知道在一定半径内是否有其他单元,而为了实现这个目标,我们使用Physics.OverlapSphere函数来探测周围碰撞体,但是这个函数的性能开销比较大,所以我们使用一个协同来运行。
寻路也在这个脚本实现,我们继续使用A*,当计算好集群行为的操控力和路径时,需要把他们结合到一起,并且作用于角色控制器,在Update函数中应用这些力并进行位置更新。下面是Boid.cs代码:
好了,到这里就基本差不多了,我们运行工程,随便双击一个地方,就可以看到小队一起移动到我们要去的目的地了。
而且过程中不会发生太大的拥挤,如果我们取消A*,改用我们unity自带的寻路其实也是可以的,非常适合手游MMORPG方面的一些团战AI,对了,如果大家在制作的过程中,如果发现人物会到处乱转上下不停抖动,那极有可能是角色控制器范围太大造成的,AI和AI之间发生拥挤,这时候把碰撞器的范围缩小就搞定了。
















