• Unity自带寻路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赋值。
    写一段很简单的代码吧:

    using UnityEngine;
    using System.Collections;
    
    public class MoveTarge : MonoBehaviour {
        private NavMeshAgent girl;
        public Transform Target;
        private Vector3 TargetPos;
        Ray ray;
        RaycastHit hit;
        ScriptControl control;
        // Use this for initialization
        void Start () {
            girl=gameObject.GetComponent<NavMeshAgent>();
            TargetPos =gameObject.transform.position;
    
            control = Camera.mainCamera.GetComponent<ScriptControl>();
        }
        
        // Update is called once per frame
        void Update () {
            if (control == null)
            {
                control = Camera.mainCamera.GetComponent<ScriptControl>();
            }
            if(control.isOpen)
            {
                girl.walkableMask = 9;      //Default和bridge层都能通过,你可以设定walkableMask = 9,也就是1+8。
            }
            else
            {
                girl.walkableMask = 17;  //Default,Red两层
            }
            if(Input.GetMouseButtonDown(0))
            {
                 ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            }
            if (Physics.Raycast(ray,out hit,100))
            {
                TargetPos =hit.point;
            }
            
            //if(Vector3.Distance(TargetPos,gameObject.transform.position)>0.4)
            //{
            //    girl.gameObject.animation.Play("run");
               girl.SetDestination(TargetPos);
            //}
            //else 
            //{
            //    girl.gameObject.animation.Play("idle");
            //}
            
        }
    }

    下面代码绑定在相机

    using UnityEngine;
    using System.Collections;
    
    public class ScriptControl : MonoBehaviour {
        public bool isOpen;
        private string Notice;
        // Use this for initialization
        void Start () {
            isOpen=true;
            Notice ="Close";
        }
        
        // Update is called once per frame
        void Update () {
        
        }
        void OnGUI()
        {
            if(GUI.Button(new Rect(Screen.width/2-30,10,60,30),Notice))
            {
                if(isOpen==true)
                {
                    isOpen=false;
                    Notice ="Open";
                }
                else
                {
                    isOpen=true;
                    Notice ="Close";
                }
            }
        }
        void OnAnimatorMove()
        {
            Animator animator = gameObject.GetComponent<Animator>();
            if (animator)
            {
                Vector3 newPostion = transform.position;
                newPostion.z -= animator.GetFloat("RunSpeed") * Time.deltaTime*5;
                transform.position = newPostion;
            }
        }
    }


    可以了,就是这么简单。
    这里为了简便,把赋值写在了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。

  • 相关阅读:
    MyEclipse数据库反向生成实体类
    Struts2部分标签
    如何使用 Jmeter 发送 Json 请求
    [转]Perfmon
    Jmeter 施压 SQL server数据库的时候,如何设置?
    Tomcat 安装之后,双击Tomcat.exe,无法运行成功,怎么办?
    Jmeter 在什么情况下定义多个thread group?
    Watir RAutomation VS AutoIt to deal with popup
    RAutomation 在 Watir中的使用
    AutoIt:如何处理应用程序端口被占用的情况
  • 原文地址:https://www.cnblogs.com/martianzone/p/3322936.html
Copyright © 2020-2023  润新知