1. 程式人生 > >【Unity3D】自動尋路的跳躍

【Unity3D】自動尋路的跳躍

《【Unity3D】自動尋路》(點選開啟連結)萬般好,但鎖死Y軸這點導致非常蛋疼的一個問題,我需要在自動尋路的過程允許遊戲主角進行跳躍。畢竟玩家都說了,在3D遊戲裡面不讓主角跳躍是一個很嚴重的問題,就像《阿瑪拉王國》本來做得非常好,但就是不能跳,導致大打折扣。那麼如果在Unity3D自動尋路的過程中進行跳躍呢?下面舉一個例子說明這個問題:


如圖所示,假設圖中的小球就是我們的主角,我按左鍵可以讓它自動尋路,按右鍵可以讓它跳,同時到了邊界還不會出現一堵無形的牆,小球能自然滑落的。

具體制作過程如下所示:

1、一如《【Unity3D】自動尋路》(點選開啟連結)拖Plane,整些Cube作障礙體,Sphere做主角,同時設定一個光源,並給這些東西加上材質。然後儲存場景,將Plane和Cube設定為Navigation Static,小球加上Nav Mesh Agent和Rigidbody,完成自動尋路的烘培。


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碰撞,則重新回到自動尋路的狀態。