Unity專題_導航尋路
前言:導航尋路(NavMesh)技術是一種系統內置的強大尋路算法系統,可以方便、快捷的開發出各種復雜應用,被大量應用於各種RPG、設計、動作、冒險等游戲中。
一.基本的導航尋路
我們會在本章模擬游戲開發過程中敵人的自動的尋路,繞過障礙,爬上與調下障礙物,按類別尋找屬於自己的道路、動態設置道路的障礙等。
1.新建項目:在場景中添加如下圖所示的地形系統:
2.標記場景中的所有不動的游戲對象為“尋路靜態(Navigation Static)”,我們通常把不動的游戲對象放在環境(新建的空物體方便統一的管理)下,如圖所示:
3.執行命名菜單中的Windows——>Navigation,顯示導航尋路(Navigation)窗口,如圖所示:
ok,當我們看到這個面板之后,我們先來分析一下這里面的屬性都有哪些作用吧,我們首先來分析Bake面板:
Agent Radius:烘培半徑,值越小越好。
Agent Height:角色所要通過的高度。
Max Slope:最大的坡度。當大於這個坡度是,會被丟棄。
Step Height : 台階的高度。低於這個高度時,導航網格地區會連接。
Drop Height:如果這個屬性是值是正數的話,相鄰的導航網格表面高度差低於此值時,將進行網格連接。
Jump Distance:跳躍距離。如果這個屬性的值是正數的話,相鄰導航網格表面的水平的距離低於此值的時候,將進行網格連接。
4.接下來是Object面板,如圖所示:
Navigation Static : 我們只有選中了Navigation Static 之后才能進行網格導航。
Generate OffMeshLinks:處於勾選狀態的話,網格導航可以Jump和Drop。
Navigation Area:導航網格層。
5.:Areas面板:
在尋路計算中,每個連通點都有代價屬性(Cost),在實施A*時根據代價估算決定這個點是否丟進個行走路點隊列中。在Navigation尋路導航界面下,Areas分頁下是在給導航區域分類(相當於分層的設置),以及為每個分類設置不同的消費Cost,意義在於,導航算法中會計算出的是累加起來消耗最低的路徑(不一定是視覺上最短可行的路徑)。例如:設置地面上有一灘沼澤,該地形新建一個分類,並設置為一個很高的消費。那么在正常的情況下,尋路將會繞過該區域,走其他消費更低的路徑。但若此時游戲中動態生成的物體阻擋了其他的路徑。只有該路徑可以走,那么該角色會穿過該沼澤地進行導航。
所以該界面的作用是:可以為每種地形自定義的分類,並可自定義的其他可行走的難以程度,來影響導航網格的選擇。
6.進行烘培,如下圖所示:
7.進行腳本的編寫:
public class Demo15_NavMesh : MonoBehaviour { #region 字段和屬性定義 public Transform FindDestination; //尋找的目標 private NavMeshAgent _agent; //尋路的組件 #endregion void Awake() { _agent = this.GetComponent<NavMeshAgent>(); } void Update() { //設置尋路 if (_agent && FindDestination) { //設置目標 _agent.SetDestination(FindDestination.transform.position); } } }//class_end
這樣的話就可以進行移動了。
二:使用OffMeshLik組件:
如果在我們項目中不能有很長的斜坡,如何讓主角“走上”陡峭的高處呢?這種情況下,我們可以使用Unity中提供的“OffMeshLink”組件來解決問題。
(1):我們還是對靜態的游戲對象標記為“導航靜態”,然后做烘培的處理,但是我們會發現烘培出了兩塊獨立的區域。如圖所示:
(2):這個時候我們給“梯子”增加“OffMeshLink”組件,並且設置其“Start”與“End”。因為“Start”與“End”參數的目的是標示用“OffMeshLink”連接兩個原本不相同的區域。所以不進行渲染且觸發自身的觸發檢測組件,如圖所示:
這時候我們運行程序的時候,我們的主角就可以從我們的“梯子”中爬到我們的目標的位置了。
三:網格分層:
在本小節中我們討論游戲對象走特定路徑的問題。
(1):我們先搭建最基本的場景:
(2):我們在導航窗口(Navigation)中的"Areas"面板中,添加對應的“層”:
在我們的兩個橋體中進行設置:
當我們再次的運行游戲的時候就可以看到我們兩個玩家會按照我們設置的進行移動了。
四:Nav Mesh Obstacle組件:
NavMeshObstacle是我們導航尋路中的“障礙物”組件。可以在導航尋路路徑中設置特定的“關卡”使得項目中的這些關卡可以按照劇情的需要,按照一定的觸發條件控制主角是否通過。
(1):新建我們場景的環境:
(2):編寫橋的動態開啟腳本:
public class Demo17_NavMesh_NavMeshObstacle : MonoBehaviour { #region 字段和屬性定義 private NavMeshObstacle _navMeshObstacle; //"障礙物"組件 #endregion void Awake() { _navMeshObstacle = this.GetComponent<NavMeshObstacle>(); } void Update() { //檢測鼠標左鍵的按下 if (Input.GetButtonDown("Fire1")) { if (_navMeshObstacle) { //允許通過 _navMeshObstacle.enabled = false; this.GetComponent<Renderer>().material.color = Color.green; } } if (Input.GetButtonUp("Fire1")) { if (_navMeshObstacle) { //允許通過 _navMeshObstacle.enabled = true; this.GetComponent<Renderer>().material.color = Color.red; } } } }//class_end
這時候當我們運行程序的時候,我們發現當主角靠近橋體的時候,由於受到“障礙物”組件的阻擋作用而停止前進,當我們的單擊鼠標左鍵的時候,“障礙物”會消失,主角可以繼續前進通過橋體到達我們指定的位置。
總結:導航尋路技術是目前游戲開發過程中不可或缺的核心技術之一,大量的應用在主角或者敵人的自動尋找目標等場景中。本篇博客僅介紹以上的四節,並沒有完整的介紹其他的。大家有興趣的話可以自己進行深入的研究。我自己也會在以后的開發過程中,繼續進行編寫有關於尋路的專題的博客,大家有興趣的話可以進行關注我,謝謝!