Unity寻路插件(A* Pathfinding)入门教程一:着手搭建A*寻路工程
本系列的教程文章基于 A*Pathfinding Project 4.2.8的官网教程翻译,每一章节的原文地址都会在教程最下方给出。着手搭建A*寻路工程
寻路意义在于如何找出一条从A点到B点的最优路径。这也正是这篇教程所要做的事情:教你如何搭建一个新工程,并且使用一个简单的AI来规避障碍进行移动。
这个将要写的AI并不会非常复杂,它仅仅展示了一个移动和跟随系统所需要的最简代码。如果你想要学习更高级的AI,可以深入追踪一下本篇教程里使用到的脚本源码,或者使用(追踪)插件里提供的AIPath、RichAI脚本。
下载
嗯,第一件事打个广告,去下载插件。你可以选择下载一个免费但是阉割了的版本,或者购买一个功能酷炫、狂霸拽的专业版本。
Javascript (Unityscript)
如果你习惯用UnityScript去开发,那么需要先看一下这篇介绍,告诉你如何使用JavScript开发。
本插件所有的示例都是用C#展示的,但是C#和UnityScript十分相近,应该不会太难理解。因为UnityScript是不支持可变参数的,所以你必须给一个函数传递所有的参数才能运行。如果在编译过程中出现了重载报错,可能就是这个原因,那么你需要查看一下API定义,补全参数的默认值即可。
移动平台部署(Mobile/UWP)
在移动平台开发,你可能要先看下这里:
问题排查
如果你是从旧版本升级上来的,遇到编译错误的话,首先去看下插件的升级文档:Readme_upgrading.txt。有一个通用的问题是A* Pathfinding Project里有一个相同类命名。你可以尝试修改其中一个类的名字,或者给一个类增加一个命名空间。
如果仍然有错误,最好看下这里,查询一下别人是否遇到类似问题,或者自己提一个问题。
概览
接触A* Pathfinding最先了解的应该是 astarpath.cs,它扮演者中央舞台,展示和提供所有概览功能。在AstarPath的检视面板(inspector)你可以创建和调整所有的图表和设定。注意:这个脚本全局最好只存在一个。可以从以下路径添加: 菜单栏–>Components–>Pathfinding–>Pathfinder。那么第二重要的的组件就是 Seeker.cs。Seeker组件应该绑定在每一个需要寻路的GameObject上。Seeker组件处理单位的路径调用,并对路径进行后处理。这个组件并不是必须的,但是它会让寻路变得更简单。很多控制移动的脚本都可以让AIs移动起来,诸如 AIPath、RichAI、AIlerp等。你可以使用其中一种,或者自己写一个移动脚本。参见:
最后,你可以使用一些修饰脚本来让后处理的路径变得更平滑或者更简单。如果修饰脚本和Seeker脚本绑定在同一个物体上,那么它将对所有Seeker关注的路径进行修饰和优化。参见:
视频教程
你也可以从这里查看视频教程。视频教程将提供一个更层次的方法,你将会学习如何使用一个内置的移动脚本,而不是自己去写一个自定义的。视频和文字教程覆盖面并不相同,所以你其实可以鱼和熊掌兼得。
"
或者你也可以在这里查看这篇优秀的教程(by:Gabriel Williams (Unity Cookie)):he series on making a Tower Defence game的第八部分,这个视频覆盖了大部分文字教程所讨论的东西。
新场景
呃~终于入正题了。
创建一个新场景,命名为 PathfindingTest 。然后创建一些东西让AI可以通过,再创建一些障碍来阻挡AI通行。在场景原点(0,0,0)增加一个plane并将Scale调至(10,10,10)。创建一个新的Layer(Edit->Project Settings->Tags)命名为Ground,然后将刚创建出来的plane的Layer改为Ground。然后创建一些乱七八糟的立方体(Cube)放在在Plane上当做是AIs的阻挡。记得把这些Cube的Layer命名为一个新的层“Obstacles”。
大概长这样:
添加A*
所以现在我们已经有一个地面给AI躺着了,也有一些阻挡让他们躲避了。那么接下来就要将A*寻路系统加入到场景中来正式开启寻路。
创建一个GameObject命名为A*,添加 AstarPath组件(Menu bar–>Components–>Pathfinding–>Pathfinder)。
AstarPath组件检视面板被分为几个部分。最重要的两个部分是 Graphs 区域和 下方的Scan按钮。
Graphs区域掌管了场景里所有的绘制,你可以最多添加256个,但是通常1-2个就足够了。为了简单起见,一般使用一个。
点击Graphs区域,展开后可以看到一个你可以操作的列表。这里不会全部讲解一遍,只会挑2个重要的部分说下,第一个是GridGraph用来生成网格节点,第二个是RecastGraph用来自动计算世界里的导航网格(navMesh)。(此功能只有Pro版本可以使用)
Scan按钮用来更新场景里的绘制(Graphs),这个在启动的时候就已经完成了(除非使用了缓存,但这个要在另外一个章节去讲解了)。如果你改变了一些graph的设定它也会自动更新,并且不会导致延迟。
可以使用快捷键调用,MAC上是 Cmd+Alt+S,Windows上是 Ctrl+Alt+S。
在本篇教程里我们会创建一个Grid Graph。添加完之后,点击展开检视面板如图所示:
顾名思义,一个GridGraph将会用你填写的宽高生成一个节点类型的网格。这个网格可以放置在你场景的任意位置,并且随心所欲的去旋转。
Node Size 变量可以定义一个网格或者节点的大小,在这个教程里我们定义为1。
网格的位置需要做些调整。看面板上命名为“Center”的变量,输入(-50,-0.1,-50)。-0.1的作用是避免浮点型错误。我们之前设定的场景Y坐标为0,如果这里也设置为0的话,使用射线检测的时候会遇到比较烦人的浮点报错。(比如检测高度)
为了让grid适配我们的场景,我们需求修改它的宽高,在这个例子,都设置为100之后,白色的网格边界和场景完美契合。
Height Testing
为了获得正确的节点高度,A* System会向场景发射一条射线来检查玩家点中了哪里,这些可以在Height Testing设定。
一条射线,拥有它的厚度(其实就是一条线段),可以在面板里设置。从单位的栅格上方向下发射,会击中某一个节点。如果它什么都没有击中 并且勾选了 Unwalkable When No Ground选项,就会被认定为不可行走,如果没有勾选就会被放置在最近的 Y=0的节点上。
我们需要改变一下使用的MASK参数选项,默认是使用 everything,但是这样就会包含我们的障碍层,所以我们修改一下,只包含我们之前创建的“Ground”层就好。
Collision Testing
当一个节点被放置之后,它主要用来检测是否可以行走。这个可以交给一个Sphere(球体)、Capsule(胶囊)、或者Ray(射线)。通常一个胶囊会被用作一个AI角色的载体,因为它要在世界里行走,所以胶囊的直径和高最好和角色的宽高一致,来更精确的计算碰撞。
通常情况,一个胶囊体的直径和高度会分别设置为1和2,但是这里我们为了测试会将其设置为2和2。
接下来,为了让系统能够察觉到我们布置的这些障碍,我们需要对Collision Testing的mask做些调整。这次我们将mask调整为只包含Obstacles层,因为我们不想把地面也当成障碍物呢!
万事俱备,只欠东风了。
点击Scan,等待一炷香的时间,你就会得到一个生成好的网格。惊不惊奇,意不意外?如果不出意外 你将会看到下面的图:
添加AI
没有移动的东西,怎么去做寻路测试呢?呵呵,一点也不好笑吧(作者原话)。那我们就添加一个AI来测试吧。创建一个胶囊体,然后增加一个Character Controller。将它放置在Plane上任意一个可视的点上。再绑一个Seeker组件,这是一个协助脚本,帮助其他需要调用寻路功能的脚本拉起寻路请求。并且,它还能通过绑定一些修饰脚本来让寻路路径更平滑和简单。
这个时候,你就有2个选择了,一个是使用内置的寻路脚本,或者大佬自己写一个。本篇教程推荐你做大佬,自己去写一个,这样你能更加容易的去理解这套系统是怎么工作的。
自定义寻路脚本可以看这里,传送门:
Documentation
当如如果大佬不想写,这里也为你准备了一些内置脚本啦。这些脚本比上面教程里提供的要复杂的多,他们分别叫,AIPath、AIRichAI、AILerp。
AIPath可以用于所有的情形,而AIRichAI则只能基于NavMesh。AIPath和AIRichAI相对来说行走的路径并不会特别精确,而AILerp则会进行非常精确的插值,但这种方式可能并不是真实。
选择哪种方式取决于你的游戏需要。不同的示例场景里都用了不同的实现脚本,可以自己下载示例工程去查查他们的不同之处。
这篇教程,我们直接使用AIPath吧。创建一个物体,命名为 Target并把它放置在任意一个你想让AI去的地方。给它绑上AIDestinationSetter组件。这是一个非常简单的脚本,只是为了告诉AIPath要移动到一个特定的地方。你其实可以在你工程里按照需求自己写一个自定义脚本。AIDestinationSetter 只有一个GameObject类型参数target,就是你刚才创建的那个。
点击Play按钮,AI就会朝目标移动了!脚本如何工作,以及更详细的参数含义、设定在上面提供的视频链接里都有说明了。如果你的胶囊体不移动,就搬个梯子去看看。
平滑
到此为止,你以及学会了如何创建一个简单的grid graph并且计算出寻路路径了。但是肯定有更好方法来让这些路点更加的平滑。
路径平滑和简化脚本,我们称之为路径修饰符。他们会被绑定到Seeker的同一个GameObject上。
最直接的一个就是简单的平滑修饰符。从下列路径添加:菜单栏–>Components–>Pathfinding–>Modifiers–>Simple Smooth。
修饰符所做的事情就是,将路径细分为若干次,直到每个部分都小于Max Segment Length变量所定义的长度。然后通过将点移动到彼此较为靠近的位置。修饰符有一些参数设定,这里不详细说明了,大家可以查看SimpleSmoothModifier文档说明。这个例子里你可以设置Max Segment Length为1,Iterations为5,Strength为0.25来获取较佳的体验。
所以,现在重新播放一下,路径看起来就平滑的多了,正是我们想要的。
平滑修饰符不会考虑场景里的几何图形,所以要避免滥用平滑修饰符,不然会出现路径穿透不可行走区域的BUG。
另外一个好的修饰符是 FunnelModifier,这个会大大简化路径。这个几乎只会用在NavMesh或者recast graphs中。
日志设置:
每一次系统计算出路径之后,都可以选择是否打印在控制台上。这对理解系统如何运作有巨大的帮助,并且可以帮助定位性能问题。日志打印本身也会引起性能问题,所以在releases版本里推荐禁用它。
你可以从日志的设置界面进行设置。A* Inspector -> Settings -> Debug tab
使用较少的debugging信息来提升性能,只是为了摆脱控制台本身制造的问题,如果要使用更多的调试信息来了解寻路脚本在做什么,InGame的选项可以在游戏内的GUI界面显示最新的路径日志。
结束
这是入门教程 part1的结束,希望你能学到一些东西。
在这里你继续探索教程的其他部分,或者直接深入项目去了解。
如果你想要一个表现好一点的AI,可以直接使用项目提供的AIPath脚本。
你可以继续入门教程的下一个部分,这次我们将使用navmesh。或者使用侧边的导航栏,有大量的教程告诉你如何使用这个插件。
原文链接:
页:
[1]