美文网首页unity多媒体和建模
Unity3d自带寻路Navmesh教程

Unity3d自带寻路Navmesh教程

作者: 壹米玖坤 | 来源:发表于2017-09-15 13:32 被阅读137次


    unity自从3.5版本之后,增加了NavMesh寻路的功能。在此之前,unity用户只能通过第三方插件(如Astar寻路插件)等做寻路功能。我也使用过A*寻路插件,A*的原理并不复杂,有兴趣的朋友可以自己百度一下。不过由于不是自带的功能,所以在设定网格和烘焙的过程难免会出现很多不便。NavMesh作为unity自带的功能,用法和之前的LightMapping烘焙或者遮挡剔除Occlusion Culling有很多相似之处。

    先来看看怎么在unity打开NavMesh功能的窗口吧:

    在window下拉列表中可以看到Navgation,点击:

    在原来Inspector面板的旁边会出现Navigation的面板:

    这个Objcet的面板是对应当前选择的物体的,旁边的Bake面板是对应全局选项的。结构和烘焙或者遮挡剔除是一样的。在选择了物体的情况下会出现上面的内容:

    上面的All、MeshRenderers、Terranis是对Hirarchy面板里面显示的物品选择的一个筛选过滤:

    all就是全部显示

    MeshRenderers是只显示可渲染的网格物体

    而Terrains当然就是只显示地形物体了。

    下面的是重要的选项,第一个Navigation Static选项是选择该物体是否用做寻路功能的一部分。只有勾选了这个选项,下面的其他选项才会可操作。

    OffMeshLink Generation选项是选择该物体是否根据高度、可跳跃宽带等全局的选项自动生成OffMeshLink,这个会在以后的讲解中详细说明,这次就暂时不讨论。

    Navigation Layer是对参与寻路功能的地图物体的一个分类,用层来分类,默认有三个层可以选择,当然也可以自己添加层。

    在Edit下拉列表,选择Project——NavMeshLayers

    出现了NavMesh层的管理界面:

    上面三个Buit-in Layer是系统默认的三个可选择层,我们可以在下面的User Layer里面输入自己需要的层的名称,比如我现在输入一个叫做“brigde”的层

    这时候,刚才输入的“bridge”层,就会出现在可选择的列表里面

    通过刚才的几步,NavMesh常用的几个面板我们都已经操作过了,接下来可以做一个小例子:

    在场景里面,我放了一个摄像机(Camera),一个充当地面的面片(plane),一个角色模型(man)和一个目标点物体(target)

    为了便于观察目标点的位置,我在目标点物体身上添加了Light组件让它会发光。角色模型(man)身上必须添加NavMesh组件,不然就不能寻路了。为了方便,我使用了官方的大兵模型,里面已经带有了动画和动画控制的脚本。不过这些动画的表现暂时是不重要的,你可以选择放一个胶囊或者Cube代替人物的模型。

    还记得刚开始介绍的Navigation面板吗?选择地面(plane),在Navigation面板里面里面勾选Navigation Static选项,其他的默认不改动。

    然后点击右下角的Bake面板。这时候会有一个计算的过程,曾经用过烘焙或者遮挡剔除的朋友应该对这个过程很熟悉了。

    不过和之前两个功能一样,如果你没有保存场景level,unity会提示你先保存,然后再bake。

    由于现在场景里面的物体很少,所以Bake的过程很快就结束了。

    留意看scene视窗,现在地面的颜色已经发生改变了,这是因为unity已经帮你生成了寻路用的NavMesh网格,由于现在没有遮挡的阻碍物,所以整个地面都是属于可以行走的范围。

    写一个最简单的控制脚本吧,以上是C#,由于很简单,估计用Js的朋友也能对应的写出来。

    简单的解释一下,这个脚本是直接拖放到角色(man)身上的,并把场景中的目标物体(target)拖放指定到该脚本的target变量上面进行了赋值。在脚本一开始的时候,我 先获取了man身上的NavMeshAgent脚本组件,然后在Update的过程中,man不断的进行对target的位移的一个寻路并移动到目标位置的操作。

    在进行完以上的操作后,你应该已经可以点击unity的播放按钮,然后移动目标物体(target),这时候角色模型已经可以追着目标点跑了。

    这里我还做了一个简单的鼠标点击plane设定目标点的功能,由于这个功能不在这次的讨论范围内,所以有兴趣的朋友可以自己去百度一下具体的方法。

    进行到这一步,人物已经跑起来了,但由于没有遮挡的障碍物,所以人物只是会直线的行走,看不出寻路的感觉。接下来我们就做点更复杂的:

    在场景里面添加一个Cube做为障碍物,具体的形状和位置请根据自己喜欢来调节,我是把它做成了一个长方形,并摆在了角色面前。

    和刚才对地面的操作差不多,选择遮挡物Cube,在Navigation面板里面勾选Navigation Static选项,这次的Navigation Layer要选择Not Walkable。顾名思义,这是不能行走的意思,代表了这个Cube是不能通过的。

    选择完成后,我们再次点击Bake,又是一个小等待的过程。

    Bake完成后,我们回到scene视窗。

    观察scene视窗,会发现刚才整个地面都是NavMesh的情况已经改变了,在障碍物的周围,NavMesh留出了一个缺口,这代表了角色已经不能从障碍物身上通过了。

    再次点击unity的播放按钮

    现在可以看到,人物已经可以绕着障碍物走了,我们的目的已经顺利达到了。

    这次的例子就到此结束了。

    在第二节里,我会详细的讲解高低落差、爬梯子以及跳跃等较为复杂一点的功能。然后会在第三节里面讲解分条件的寻路(不同人走不同的路),以及动态控制道路(如吊桥)等的功能。



    上一节简单介绍了NavMesh寻路的基本用法,这次来介绍一下稍微复杂一点点的高低落差以及跳跃的做法,首先来看看这次的目标:

    第一部分是爬楼梯,第二部分是横向跳跃和往下跳落

    不管是爬楼梯,还是跳跃,NavMesh都是通过了OffMeshLink来做的。创建OffMeshLink的方法有两种,接下来会通过制作上面的例子来进行说明:

    为了做这个例子,我们预先在场景里面准备了一些物体:摄像机是必须的,一个作为地面的Plane,然后是F1——F5几个高低落差不一样的台阶,L1和L2是楼梯模型, 控制人物主体man,还有移动的目标点target。

    其中man身上必须带有NavMesh Agent组件,为了观察方便在target身上带了light组件。

    按照上一节所讲的,plane和F1——F5台阶在Navigation面板勾选Navigation Static选项,然后Bake,观察Scene视窗,会发现已经生成了我们所要的NavMesh网格,现在我们可以像上一节那样在plane上面给人物做寻路和移动了,但人物是不会爬楼梯的。

    这时候,我们找到L1楼梯,在楼梯的开始和结束的位置放置两个点,这两个点只需要拾取它的位移的,你可以用empty Gameobject来做,我这里为了便于观察,就拿了cube来做。开始点命名为startPoint,结束点命名为endPoint。

    注意:startPoint和endPoint的位置要稍微比所在的平面高一点点。

    接下来介绍第一种生成OffMeshLink的方法。选择L1楼梯,然后在Component下拉选项中选择Navigation——Off Mesh Link。

    选择后,OffMeshLink组件已经添加到了L1的身上,我们可以在Inspector面板看到:

    我们把刚才放置在场景里面的startPoint和endPoint指定到OffmeshLink组件的Start和End位置,其他选项默认不改变

    再次Bake

    现在我们发现,在scene面板里面,在startPoint和endPoint之间生成了一条线,而方向是从startPoint指向endPoint的。

    这时候,你应该可以通过移动目标点让角色开始爬楼梯了。但爬上去之后角色暂时不能跳下来,如果把目标点移动到plane上,角色会顺着楼梯爬下来。

    我们使用同样的方法对L2进行生成OffMeshLink。这时候,角色应该可以爬两层楼梯了。到此第一个目标完成了。

    接下来我们进行第二个目标的制作,首先先来分析一下我们的场景:

    我们希望人物能从2.5M的高度往下跳,超过2.5M人物就不能跳了,太高会有危险。然后横向我们希望人物能跳过2米的沟。

    根据这个设定,我们的场景会是这样的情况:L1和L2只能通过爬楼梯,L2和L3之间可以跳跃,L3——L5是可以往下跳的。

    于是,我们在Navigation面板里面找到Bake栏,Drop Height(掉落高度)填2.5,Jump Distance(跳跃距离)填2,单位都是米

    接下来介绍第二种生成OffMeshLink的方法:

    我们把L1——L5的物体选中,在Navigation面板的Object栏里面把OffMeshLink Generation选项打上勾

    再次Bake,回到scene视窗:

    这时候,场景里面会出现很多心的OffMeshLink,这是unity通过计算,把可以跳跃或者下落的地方自动生成了OffMeshLink了。

    这时候,你应该已经可以通过移动目标点,让角色进行跳跃和下落了。

    进行到这里,我们的第二个目标也完成了。

    不过有些朋友可能会提出疑问,在做的过程中,假如没有这个大兵的模型,而是用一个胶囊体来代替人物的话,它爬楼梯和跳跃的时候好像是在一瞬间完成的,没有大兵那个爬楼梯和跳跃动作的过程。如这样:

    的确是这样,因为默认的NaveMesh Agent组件上面是勾选了Auto Traverse Off Mesh Link(自动通过OffMeshLink)选项的。这样的意思是人物只要到了OffMeshLink的开始点,就会自动的移动到OffMeshLink的结束点。

    假如各位需要对越过OffMeshLink时候进行自己的控制,是需要另外写脚本的。我这里简单的介绍一下方法,有兴趣的朋友可以自己试试。

    首先各位最好有用状态来控制角色的概念。比如人物可以分为站立、走路、跑步、上下楼梯、横向跳跃和往下掉落几种状态,针对NavMesh来说,人物简单的可以分为站立、正常的NavMesh寻路,和通过OffMeshLink移动几种状态。

    先把 Auto Traverse Off Mesh Link选项取消。

    然后,当人物在通过OffMeshLink移动的状态(可以用NavMeshAgent.isOnOffMeshLink来判断),获取到当前通过的OffMeshLink:

    OffMeshLinkData  link = NavMeshAgent.currentOffMeshLinkData;

    这样你就能获取到link的开始点和结束点的坐标(link.startPos和link.endPos),这时候你的人物就可以用最简单的Vector3.Lerp来进行移动,当人物的位移到达了结束点的坐标,人物的OffMeshLink移动状态就可以结束,又重新变回正常寻路或者站立的状态了。在这个Vector3.Lerp的过程中,你可以随意的控制人物的爬行或者跳跃的动作。

    到这里,第二节的内容结束了。到现在,各位应该已经可以基本掌握了NavMesh寻路的全部正常操作了。接下来,我会在第三节里面简单讲解一下NavMesh的稍微复杂的控制方法,希望大家继续支持阿赵。

    顺带一提,可能很多朋友希望我把工程文件提供下载。不过我觉得这样并不是一件好事,因为这几个例子都是很简单的操作,如果各位有耐心跟着阿赵一步步的做下来,应该可以得到你想要的结果。而如果没有耐心一步步的看下来,直接看工程文件,可能会忽略了很多重要的步骤的。



    继续介绍NavMesh寻路的功能,接下来阿赵打算讲一下以下两个例子,先看看完成的效果:

    第一个例子对于喜欢DOTA的朋友应该很熟悉了,就是不同小队分不同路线进攻的寻路,红绿蓝三个队伍分别根据三条路线进攻。

    第二个例子是动态的控制道路的开关。当吊桥打开时,道路不通,当吊桥放下时,道路可以通行。

    先来说说第一个例子吧,第一个例子其实很简单,只需要在之前两节的基础上修改一下层的设置就可以了。

    先来分析一下我们的地形,为了做这个例子,我准备了两个plane分别作为我方基地和地方基地,然后用plane简单的拼了三条线路。

    在我方基地,准备了红绿蓝各三个的小兵(用胶囊代替)。当然小兵身上带着NavMesh Agent组件

    如果把两个plane和三条线路都打上Navigation static的话,就和普通的寻路没有区别,三条路都能走。接下来我们进行层的设置。

    还记得第一节里面讲过的怎么设置NavMeshLayer吧?

    现在我们需要设置Red、Blue和Green三个层,如上图所示。

    现在,我们可以选择路线一,然后在Navigation Layer里面选择Red层了。相应的,路线二选择Blue层,路线三选择Green层

    Bake出来后,会是上面的效果。

    道路已经设置好了接下来我们对小兵身上的NavMesh Agent组件进行设置

    选择蓝色的小兵,然后找到NavMesh Agent组件里面的NavMesh Walkable选项,这里就是人物能通过的层的选择了。按照刚才层的设计,蓝色的小兵需要勾选Blue层 ,把Red层和Green层取消选择。

    同理,把红色小兵和绿色小兵的NavMesh Walkable层处理一下。

    现在,我们可以运行了,移动目标点到敌方基地,三种不同颜色的小兵就会根据不同的路线寻路进攻了。

    我们第一个目标也就完成了。

    接下来说一下第二个例子

    这个例子我准备了两个平台,中间是一个活动的吊桥,一个带NavMesh Agent组件的角色模型,一个目标点

    如果按照之前的操作,我们可以轻易的让角色在任意位置寻路,但为了让吊桥升起的时候角色不能通过吊桥,我们需要对吊桥的NavMesh层进行一些设置。

    和刚才一样,我们要预先设置了一个叫做bridge的层(在第一节的时候做过)。

    同样的,吊桥选择bridge层

    这里的操作和上面的例子没什么区别,但这次角色身上的NavMesh Walkable不需要设置,直接Everything就行了。

    到了这里,我们需要通过脚本来控制人物是否能通过吊桥。这里需要用NavMeshAgent.walkableMask来动态修改NavMesh Walkable的值。

    关于吊桥怎样升降,这不是本次讨论的内容,你可以选择直接用位移来控制,或者吊桥直接做好开关的动画也行。

    之前说过,各位最好要有习惯用状态来控制物体。这里的吊桥会有2种状态,一种是开状态,一种是关状态。当开状态时,吊桥断开,人物不能通行,关状态时,吊桥闭合,人能通行。给予这两种状态,我们给人物身上的NavMeshAgent.walkableMask赋值。

    写一段很简单的代码吧:

    可以了,就是这么简单。

    这里为了简便,把赋值写在了UpDate里面,其实这样做是不正确的,没必要每帧都检测赋值,只需要把这个赋值写在吊桥开关的控制里面就行了。

    我来解释一下其中的意思:

    定义了一个状态的开关open,当吊桥打开时open= true;当吊桥闭合时,open = false;至于这个状态时怎样赋值的,各位可以自己试试想办法。

    然后假设这个脚本是放置角色身上的,那么在start的时候就获取角色身上的NavMesh Agent组件。当然了,你也可以把脚本放在其他的地方,然后通过赋值来指定agent。

    当open为true的时候,人物的walkableMask = 1,意思是只有第一层(就是默认的Default)可以让玩家通行。

    当open为false的时候,人物的walkableMask = -1,意思是所有层(Everything)都可以让玩家通过。

    从自定义层的界面我们可以总结一下,每一个层的可通过值,其实就是全面所以层的值相加的总和再加1。或者说是2的(n-1)次方。

    除了指定本身的层意外,还可以指定多个层,比如这里假如你想mix一个Default和bridge层都能通过,你可以设定walkableMask = 9,也就是1+8。

    到此为止,阿赵我对于Unity自带的NavMesh寻路的介绍就结束了。至于NavMesh或者NavMesh Agent组件的各个属性和方法,API文档里面有具体的说明,有兴趣可以具体去看看,我就不一一解释。有很多变化的用法,各位可以自己尝试一下。谢谢大家的支持!

    来自作者:阿赵


    相关文章

      网友评论

        本文标题: Unity3d自带寻路Navmesh教程

        本文链接:https://www.haomeiwen.com/subject/gsmssxtx.html