2016年7月21日 星期四

【Unity】使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

本文章會提到的‧
滑鼠點擊地板的人物移動3D與2D射線中提到的射線(Ray)。
Unity導航系統前三篇。
Mecanim動畫系統Part1Part3Part4

本文開始。
這次要做的是,使用滑鼠點擊地板的人物移動操控。
移動路徑規劃使用導航網格(NavMesh),移動目標位置使用射線(Ray)指定,人物動畫則是使用Mecanim動畫系統
成果如下圖。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

在開始實作目標之前,需要先把物件準備好,第一個是地板物件Floor。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動
使用Plane物件,新增tag命名為Floor並且選取,接著點擊Static下拉選單,選取Navigation Static。

接著是障礙物物件Obstacle。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動
使用Cube物件,新增tag命名為Obstacle並且選取,新增元件Nav Mesh Obstacle,然後勾選Carve選項。

最後是人物模型。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動
這裡使用UnityChan的人物模型,在模型下新增元件Nav Mesh Agent。

將地板、障礙物和人物模型都準備好後,就可以開始實作這次的目標。
第一步是產生導航網格(NavMesh),Window -> Navigation開啟導航視窗,點選Bake,也就是烘焙生成導航網格。
如果場景沒存檔,Unity會告訴你要存檔。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

烘焙(Bake)完成後,可以在場景中看到藍色的網格,如下圖。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

接著點選人物模型,新增控制用腳本,腳本內容如下。
using UnityEngine;
public class Move : MonoBehaviour {
    private NavMeshAgent agent;////(1)
    private Vector3 target;
    void Start () {
        agent = GetComponent<NavMeshAgent>();////(2)
        target = transform.position;
    }
    void Update () {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);////(3)
        RaycastHit hit;
        if (Input.GetMouseButtonDown(0) ////(4)
            && Physics.Raycast(ray, out hit) 
            && hit.transform.gameObject.tag == "Floor")
        {
            target = hit.point;////(5)
        }
        agent.SetDestination(target);////(6)
    }
}
(1)腳本中有兩個重要變數,target負責記錄滑鼠點擊的位置,agent抓取target位置後移動。
(2)在Start初始化時,agent抓取模型下的元件,target設定目標位置,這裡就給它模型位置作為初始化的數值。
(3)取得攝影機到滑鼠位置的射線。
(4)當滑鼠點擊左鍵時 & 射線有打到物體 & 該物體的標籤為Floor時,判斷式成立。
(5)將target位置設定為點擊的位置。
(6)將agent的目標設為target。

執行後點擊地板,應該可以看到以下結果。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動
到這裡會依照點擊的位置移動,而且帶有迴避障礙物的功能,移動的的部分就算是完成了。

最後追加人物的動畫當作修飾,讓Unity醬動起來好看一點。
在模型下新增元件Animator,並且在專案中新增Animator Controller檔案後代入Animator元件
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

選取Window -> Animator,或雙擊Animator Controller檔案開啟動畫編輯視窗,接著將準備好的動畫,待機與移動拖曳至動畫編輯視窗。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

在動畫上右鍵選取Make Transition,建立兩個動畫之間的轉換,然後在Parameters中新增浮點數speed。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

選取轉換的線,將Has Exit Time的勾選取消,Conditions新增動畫轉換的門檻,待機到移動為大於(Greater),移動到待機為小於(Less),數值這裡設定為0.01
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動

開啟人物模型的控制腳本,加入紅字的程式碼。
using UnityEngine;
public class Move : MonoBehaviour {
    private NavMeshAgent agent;
    private Vector3 target;
    private Animator animator;
    void Start () {
        agent = GetComponent<NavMeshAgent>();
        target = transform.position;
        animator = GetComponent<Animator>();
    }
    void Update () {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Input.GetMouseButtonDown(0) 
            && Physics.Raycast(ray, out hit) 
            && hit.transform.gameObject.tag == "Floor")
        {
            target = hit.point;
        }
        agent.SetDestination(target);
        animator.SetFloat("speed", agent.velocity.sqrMagnitude);
    }
}
以下是執行結果。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動
嗯‧‧‧有移動太快旋轉太慢的問題,將agent元件的參數Speed調整為2,Angular Speed調整為360。

再執行一次看看結果。
使用導航網格(NavMesh)實踐滑鼠點擊地板的人物移動
看起來好多了,以上就是加上導航網格的點擊地板移動,和先前相比,透過導航網格可以做出非直線的移動,同時也多了迴避障礙物的功能
這次就到這裡。

素材連結:
Unity醬~~

以及

地板

沒有留言:

張貼留言

【自製小遊戲】水平思考猜謎(海龜湯)

遊戲連結 海龜湯的玩法是由出題者提出一個難以理解的事件,參與猜題者可以提出任何問題以試圖縮小範圍並找出事件背後真正的原因。但出題者僅能以「是」、「不是」或「沒有關係」來回答問題。 本遊戲蒐集各種論壇、平台的42個題目,提供給想玩海龜湯卻愁找不到題目的你們。 ...