【Unity3D】自动寻路的跳跃教程

分类栏目:unity3d教程

422

《【Unity3D】自动寻路》万般好,但锁死Y轴这点导致非常蛋疼的一个问题,我需要在自动寻路的过程允许游戏主角进行跳跃。毕竟玩家都说了,在3D游戏里面不让主角跳跃是一个很严重的问题,就像《阿玛拉王国》本来做得非常好,但就是不能跳,导致大打折扣。那么如果在Unity3D自动寻路的过程中进行跳跃呢?下面举一个例子说明这个问题:

【Unity3D】自动寻路的跳跃教程

如图所示,假设图中的小球就是我们的主角,我按左键可以让它自动寻路,按右键可以让它跳,同时到了边界还不会出现一堵无形的墙,小球能自然滑落的。

具体制作过程如下所示:

1、一如《【Unity3D】自动寻路》拖Plane,整些Cube作障碍体,Sphere做主角,同时设置一个光源,并给这些东西加上材质。然后保存场景,将Plane和Cube设置为Navigation Static,小球加上Nav Mesh Agent和Rigidbody,完成自动寻路的烘培。

【Unity3D】自动寻路的跳跃教程

2、给小球赋予GameScript.cs如下所示,则完成:

using UnityEngine;

using System.Collections;

public class GameScript : MonoBehaviour

{

    private NavMeshAgent navMeshAgent;

    private bool is_jumping, out_of_bound;//用于设置小球是否跳跃和已经到达自动寻路边缘的flag

    void Start()

    {

        navMeshAgent = gameObject.GetComponent<NavMeshAgent>();//初始化navMeshAgent  

        is_jumping = false;

        out_of_bound = false;

    }

    void Update()

    {

        if (Input.GetMouseButtonDown(0) && !is_jumping && !out_of_bound)

        {//如果不是在跳跃、不是到达自动寻路边缘,按下鼠标左键   

            //自动寻路

            Ray mRay = Camera.main.ScreenPointToRay(Input.mousePosition);

            RaycastHit mHit;

            if (Physics.Raycast(mRay, out mHit))

            {

                if (mHit.collider.gameObject.name == "Plane")//如果点的是Plane上的一点

                {

                    this.rigidbody.velocity = new Vector3(0, 0, 0);//这里是考虑到跳跃落地之后,用户马上要自动寻路的情况

                    navMeshAgent.SetDestination(mHit.point);

                }

            }

        }

 

        if (Input.GetMouseButtonDown(1) && !is_jumping && !out_of_bound)//按下鼠标右键的话

        {

            Ray mRay = Camera.main.ScreenPointToRay(Input.mousePosition);

            RaycastHit mHit;

            if (Physics.Raycast(mRay, out mHit))

            {

                if (mHit.collider.gameObject.name == "Plane")

                {

                    navMeshAgent.enabled = false;//取消自动寻路

                    is_jumping = true;//让小球进行跳跃

                    this.rigidbody.velocity = new Vector3(0, 0, 0);

                    this.rigidbody.velocity = mHit.point + new Vector3(0, 5, 0);//基于一个点击位置方向加上y=5的向量速度

                }

            }

 

        }

        if ((this.transform.position.x > 4.6 && this.rigidbody.velocity.x > 0.01) ||

            (this.transform.position.x < -4.6 && this.rigidbody.velocity.x < -0.01) ||

            (this.transform.position.z > 4.6 && this.rigidbody.velocity.z > 0.01) ||

            (this.transform.position.z < -4.6 && this.rigidbody.velocity.z < -0.01))

        {//如果已经到了Plane的边缘

            out_of_bound = true;

            navMeshAgent.enabled = false;//关闭自动寻路

        }

 

        if (this.transform.position.y < -3)//如果小球已经掉得太下方

        {

            Application.LoadLevel("Navmesh_jump");//重新开始

        }

    }

 

    //小球如果和Plane开始碰撞

    void OnCollisionEnter(Collision collision)

    {

        if (collision.collider.gameObject.name == "Plane" && is_jumping)

        {

            is_jumping = false;

            navMeshAgent.enabled = true;//重新打开自动寻路

        }

    }

 

}

这里的难点就是因为自动寻路Nav Mesh Agent锁死了Y轴,导致和刚体Rigidbody想在3D世界中自由进行物理运动产生冲突,那么我们在小球需要跳跃的时候就不要这个自动寻路好了,同时自动寻路Nav Mesh Agent一旦小球到达了Plane的边界也会不知道为何会自动产生一股无形的墙,非要小球不能滑落,这里也和刚体Rigidbody产生冲突的,我们也是需要解除自动寻路Nav Mesh Agent,让小球得以滑落。

综上所述,其实来来去去是如果协调好自动寻路Nav Mesh Agent在何时开关的问题。这里在设置两个flag之后,在用户点击右键则让小球进行跳跃状态,执行《【Unity3D】用鼠标点击事件、AddForce完成跳跃与二段跳》(点击打开链接)对跳跃的处理,然后用到《【Unity3D】利用物体碰撞检测、键盘输入处理完成平衡球游戏》对碰撞检查的内容,设置进行跳跃状态的小球一旦与Plane碰撞,则重新回到自动寻路的状态。