Unity中Navigation组件的使用代码范例和注意事项

发表于2017-12-02
评论0 2.8k浏览

告诉大家Unity中Navigation组件的使用代码范例和注意事项主要是让大家以后可以有效快速的实现自己的需求,要知道Unity中的Navigation为我们开发游戏的寻路功能提供了极大的帮助。


有以下几个注意点:

  • 设置了 navmesh之后 要bake 也就是烘焙之后 才有效果
  • 相关的参数调节在Window->Navigation下
  • 参与成为寻路障碍的物体在相关Navigation的标签下选中Navigation Static
  • 一个单一的场景最多支持1024个各条寻路路径互相连通而生成的小方块
  • 寻路物体加上Nav Mesh Agent组件


下面是视频里的代码,脚本放到寻路物体身上,记得加上NavMeshAgent组件,亲测可用:

public class Navigation : MonoBehaviour {  
    public GameObject particle = null;//Prefab物体,用来点击地图以后作为临时生成物指示寻路目标地点  
    protected NavMeshAgent agent;  
    protected Animator animator;  
    protected Object particleClone;//prefab的临时生成物的引用  
    // Use this for initialization  
    void Start () {  
        agent = GetComponent<NavMeshAgent>();  
        agent.updateRotation = false;//不使用NavMeshAgent组件的导路时的方向  
        animator = GetComponent<Animator>();  
    }  
    protected void SetDestination()  
    {  
        var ray = Camera.main.ScreenPointToRay(Input.mousePosition);//获取穿过摄像机和鼠标点击位置的射线  
        RaycastHit hit = new RaycastHit();  
        if (Physics.Raycast(ray ,out hit))//射线碰撞检测  
        {  
            if (particleClone)//再次点击之后,销毁之前点击生成的物体  
            {  
                GameObject.Destroy(particleClone);  
                particleClone = null;  
            }  
            //function SetLookRotation (view : Vector3, up : Vector3 = Vector3.up) : void   
        // 建立一个旋转,使z轴朝向view ,y轴朝向up    
            Quaternion q = new Quaternion();  
            q.SetLookRotation(hit.normal, Vector3.forward);  
            particleClone = Instantiate(particle, hit.point, q);  
 //设置或更新的目标。这会触发一个新的路径计算。  
            agent.destination = hit.point;  
        }  
 }  
    void Update()  
    {  
        if (Input.GetKeyDown(KeyCode.Mouse0))  
        {  
            SetDestination();  
        }  
    }  
}  

在实现的时候遇到了一些问题,就是当寻路物体加了Rigidbody组件之后会出现物体抽风的现象,后来发现rigidbody的usegravity选项取消勾选之后就不会了,这里我猜测一下,如果RigidBody的Inspector面板上x,z方向的Rotation以及y方向的Position都Freeze掉的话,应该也不会出现抽风现象。网上随意搜了一下,有一篇文章写得好,在这里分享一下:

这两天弄一个角色寻路的问题,总是会出一些问题,最终是因为混用了Rigidbody和NavMeshAgent所致。Rigidbody、CharacterController和NavMeshAgent这三者到底是什么关系,经过一番搜索和测试,基本上弄明白了这三者的差别:

Rigidbody是用来模拟真实物理效果的,它可以设置重力,可以为对象施加外力。注意它和各种Collider的关系:只有Rigidbody才能被施加外力,这个力可能是被直接施加的,也可能是被其它Rigidbody碰撞产生的间接力;而Collider是用来设置碰撞的一些参数。简单说:没有Rigidbody就不会动,没有Collider就不能碰撞或被碰撞。这个用于赛车类需要真实物理效果的游戏比较合适。


CharacterController除了重力效果之外,它是不能受物理力的。本身自带了一个胶囊碰撞体,可以用来产生碰撞。只有调用Move或SimpleMove,对象才能移动。所以它被称为角色控制器,一般的角色操作类游戏用这个比较合适。


NavMeshAgent属于寻路系统,它也带有一个圆柱体形的碰撞体。如果两个这样的对象相遇,就会产生推动效果。寻路过程的计算细节并不清楚,但根据测试,应该也是用物理系统去模拟了一些计算(之所以会和物理系统产生冲突,可能就是因为这个原因)。具体如何运用:如果你的角色要寻路,那么添加了NavMeshAgent后就不要再添加Rigidbody或CharacterController,如果要对另外一个动态对象产生碰撞,就为那个对象加上Navmesh Obstacle组件。如果不进行寻路操作,那么CharacterController和Rigidbody也不要混用。如果对象之间需要产生真实的推力效果,就用Rigidbody;否则,用CharacterController。如果真有复杂的混用情况,也可以在代码中根据情况,启用或禁用相应组件。不过建议不要这样做,因为一旦出了问题,你无法调试。要从设计上就避免这些复杂的情况。备注 :用Navigation系统,有时需要判断是否达到了目的地,需要进行如下判断:

if (!navAgent.pathPending)    
{    
    if (navAgent.remainingDistance <= navAgent.stoppingDistance)    
    {    
        if (!navAgent.hasPath || navAgent.velocity.sqrMagnitude == 0f)    
        {    
            //find path done!    
        }    
    }    
}    


最后有一个地方自己栽了好久,要提醒一下。如下代码:

void Update () {  
        if (Vector3.Distance(transform.position, player.position) < 1.3f)  
        {  
            agent.Stop();  
            anim.SetBool("Move", false);  
        }  
        else  
        {  
            agent.ResetPath();  
            anim.SetBool("Move", true);  
            agent.SetDestination(player.position);  
            agent.Resume();  
        }  
    }  


当寻路物体与寻路目标的距离小于既定目标距离时,调用了stop方法停止寻路后,距离又大于既定距离了,这时寻路物体不会自动寻路,通过调用agent.ResetPath()和agent.Resume()方法都可以让寻路物体恢复寻路,但是agent.ResetPath()方法会使得当你的寻路物体过多的时候,代码控制的新产生的寻路物体的agent.SetDestination()函数失效,效果就是新产生寻路物体的物体不会走了,只有当角色与新产生的寻路物体考得足够近时其才会寻路,走远后又不会寻路了。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引