前言:在游戲中經(jīng)常出現(xiàn)怪物自己會(huì)走路,人物跟隨鼠標(biāo)點(diǎn)擊位置進(jìn)行移動(dòng),那么這些功能是怎么實(shí)現(xiàn)的呢?通過(guò)本節(jié)內(nèi)容的學(xué)習(xí),你會(huì)對(duì)自動(dòng)尋路的原理有一個(gè)初步的認(rèn)識(shí)。當(dāng)然了如果想像英雄聯(lián)盟里面的人物那樣帶點(diǎn)擊的特效的話,還需要用到粒子系統(tǒng)方面的知識(shí),好了,廢話不多說(shuō)了,咱們開(kāi)始吧
1. 認(rèn)識(shí)網(wǎng)格導(dǎo)航組件
Nav Mesh Agent(網(wǎng)格導(dǎo)航代理)

- Radius:agent的半徑,用于計(jì)算該agent和其他agent、obstacle的碰撞。
- Height:agent的高度,agent可以通過(guò)的頭頂障礙最小高度。
- Base offset:agent圓柱碰撞體中心點(diǎn)的偏移值。當(dāng)Agent創(chuàng)建后,圓柱碰撞體顯示過(guò)高或過(guò)低,用于將其調(diào)整到地面。
- Speed:agent移動(dòng)的最大速度(世界空間中以秒單位計(jì)算)
- Angular Speed:agent最大的旋轉(zhuǎn)速度(角度每秒)
- Acceleration:agent最大的加速度(世界空間單位每秒的平方)
- Stopping distance:agent靠近目標(biāo)時(shí)停下的距離
- Auto Braking:自動(dòng)剎車,當(dāng)啟用的時(shí)候agent會(huì)在到達(dá)終點(diǎn)時(shí)慢慢停下,你應(yīng)該在角色需要平滑地巡邏幾個(gè)固定點(diǎn)時(shí),禁用它。
- Quality:障礙回避的質(zhì)量值,如果你有大量的agent就可以降低該值節(jié)約CPU的資源,將它設(shè)置為0,則只會(huì)處理碰撞,不會(huì)嘗試規(guī)避其他agent和obstacle。
- Priority:agent會(huì)重視該值比自己小的,而忽略該值比自己大的。該值范圍為0到99,數(shù)字越低意味著高權(quán)限,權(quán)限越高(越小的值)會(huì)被其他agent重視而回避。
- Auto Traverse OffMesh Link:需要agent自動(dòng)通過(guò)off-mesh link的時(shí)候設(shè)置為true,當(dāng)想要使用動(dòng)畫或其他特殊的方法通過(guò)off-mesh link時(shí)設(shè)為false。
- Auto Repath:?jiǎn)⒂脮r(shí),agent會(huì)在到達(dá)局部路徑的終點(diǎn)時(shí),嘗試再次尋找路徑。當(dāng)沒(méi)有通向目標(biāo)的路徑時(shí),它會(huì)生成一個(gè)離目標(biāo)最近的點(diǎn)作為當(dāng)前的一個(gè)目標(biāo)。(我嘗試下來(lái)發(fā)現(xiàn),當(dāng)目標(biāo)點(diǎn)不可達(dá),勾選該選項(xiàng)的agent嘗試尋找臨近目標(biāo)點(diǎn)的欲望比不勾選的要大)
- Area Mask:AreaMask描述了agent會(huì)在哪些烘培的區(qū)域中尋找路徑。當(dāng)你準(zhǔn)備烘培NavMesh時(shí),你可以指定區(qū)域的類型,比如你想讓階梯作為一個(gè)特殊的區(qū)域,并且禁止某些角色使用階梯。
在使用Agent的時(shí)候,大家可能發(fā)現(xiàn)了Agent有Radius屬性,在我們烘培NavMesh的時(shí)候設(shè)置的圓柱體也有Radius屬性,兩者有什么區(qū)別呢?
在尋路的時(shí)候有兩個(gè)階段,第一階段只考慮烘培NavMesh并尋找一條可行的路徑,而第二階段Agent就已經(jīng)在前往目的地的路上了,它會(huì)考慮其他agent和obstacle,并盡量避開(kāi)他們。
烘培時(shí)候的Radius就對(duì)應(yīng)第一階段的生成NavMesh,而Agent上的Radius只在第二階段使用。就比如說(shuō),有一條小徑,你有一只大怪是通過(guò)不了該路徑的,但烘培時(shí)候的Radius設(shè)置的比較小,雖然Agent的Radius可能設(shè)置的很大,但這只大怪還是會(huì)使用該小徑通過(guò)。
所以要理解尋路的兩個(gè)階段,再?gòu)?qiáng)調(diào)一遍,第一階段沒(méi)有開(kāi)始真正的尋路不考慮其他的agent和obstacle,只看NavMesh,而第二階段Agent已經(jīng)在行走,而會(huì)盡量避開(kāi)其他agent和obstacle。
Off Mesh Link(分離網(wǎng)格連線)
OffMeshLink組件允許你在區(qū)域中給Agent提供一些小近路,使Agent能快速通過(guò),比如跳過(guò)柵欄、通過(guò)一扇門。

- Start:物體描述的開(kāi)始點(diǎn)。
- End:物體描述的結(jié)束點(diǎn)。
- Cost Override:如果該值是正的,使用它在處理需求路徑時(shí)計(jì)算路徑的代價(jià)值,否則會(huì)使用默認(rèn)的代價(jià)值(游戲物體所屬區(qū)域的代價(jià)值)。如果代價(jià)值設(shè)置超過(guò)3.0,經(jīng)過(guò)該off-mesh link會(huì)比經(jīng)過(guò)三倍的默認(rèn)NavMesh區(qū)域還多。當(dāng)你想用Agent初始化偏愛(ài)的路徑時(shí),該代價(jià)值非常有用。當(dāng)然最好是在移動(dòng)中清晰比較長(zhǎng)的距離中使用。
- Bi Directional:如果啟用,則該link是雙向的,否則只能從Start到End。
- Activated:指定該link會(huì)不會(huì)在尋路的時(shí)候使用(在設(shè)置為false的時(shí)候被忽略)
- Auto Update Position:?jiǎn)⒂玫臅r(shí)候,Off-Mesh Link會(huì)自動(dòng)重新連接start和end的坐標(biāo),如果禁用,則只使用啟用時(shí)候的坐標(biāo),即使后來(lái)坐標(biāo)移動(dòng)了也不會(huì)改變。
- Navigation Area:描述link所屬的NavMesh區(qū)域類型,該區(qū)域類型會(huì)允許你在相似類型區(qū)域中應(yīng)用該區(qū)域的通路代價(jià)值,并且防止一些特定的Agent使用該通路,使用Agent的AreaMask屬性來(lái)控制。
Nav Mesh Obstacle(網(wǎng)格導(dǎo)航障礙)

- Shape:obstacle的幾何形狀,選擇物體最合適的形狀,有兩種Box方塊和Capsule膠囊體。
- Box/Center:方塊形狀的中心點(diǎn),與Transform的Position有關(guān)。
- Box/Size:方塊的大小尺寸。
- Capsule/Center:膠囊體形狀的中心點(diǎn),與Transform的Position有關(guān)。
- Capsule/Radius:膠囊體的半徑。
- Capsule/Height:膠囊體的高度。
- Carve:當(dāng)Carve該選項(xiàng)被勾選,Obsacle該物體會(huì)在NavMesh上制造一個(gè)空洞。
- Move Threshold:Unity會(huì)在Obstacle移動(dòng)該距離下,將其處理為移動(dòng)狀態(tài),使用該屬性設(shè)置移動(dòng)更新Carve空洞的頻率。
- Time To Stationary:Obstacle停止運(yùn)動(dòng)后,經(jīng)過(guò)多少時(shí)間(秒)會(huì)被處理為靜止?fàn)顟B(tài)。
- Carve Only Stationary:?jiǎn)⒂脮r(shí),Obstacle僅會(huì)在靜止時(shí)被處理成空洞,詳見(jiàn)官方文檔(廢話)。這里有幾個(gè)小細(xì)節(jié)需要注意,禁用該選項(xiàng)時(shí),空洞的重新計(jì)算是隔一幀計(jì)算一次,就是兩幀計(jì)算一次。然后最好啟用該選項(xiàng),因?yàn)槊看慰斩吹闹匦掠?jì)算比較費(fèi)時(shí)。官方文檔中舉了兩個(gè)適用的場(chǎng)景:木桶、箱子之類會(huì)受力停止的啟用選項(xiàng),而像坦克緩慢移動(dòng)的,則可以禁用該項(xiàng)。
Navigation面板(導(dǎo)航面板)
Agents(網(wǎng)格導(dǎo)航代理)

- Agent Types:導(dǎo)航代理類型
- Name:導(dǎo)航代理名字
- Radius:導(dǎo)航代理半徑
- Height:導(dǎo)航代理高度
- Step Height:能上去的臺(tái)階高度
- Max Slope:最大的坡度
Areas(導(dǎo)航區(qū)域)

- 前三個(gè)是Unity內(nèi)置的Walkable(能走的),Not Walkable(不能走的),Jump(跳)
- 其他的用戶用來(lái)自定義
Bake(烘焙參數(shù)面板)

- Radius:具有代表性的物體半徑,半徑越小生成的網(wǎng)格面積越大。
- Height:具有代表性的物體的高度。
- Max Slope:斜坡的坡度。
- Ste Height:臺(tái)階高度。
- Drop Height:允許最大的下落距離。
- Jump Distance:允許最大的跳躍距離。
- Min Region Area:網(wǎng)格面積小于該值則不生成導(dǎo)航網(wǎng)格。
- Width Inaccuracy:允許最大寬度的誤差。
- Height Inaccuracy:允許最大高度的誤差。
- Height Mesh:勾選后會(huì)保存高度信息,同時(shí)會(huì)消耗一些性能和存儲(chǔ)空間。
Object(物體參數(shù)面板)

- Navigation Static:勾選后表示該對(duì)象參與導(dǎo)航網(wǎng)格的烘培。
- OffMeshLink Generation:勾選后可跳躍(Jump)導(dǎo)航網(wǎng)格和下落(Drop)。
- Navigation Area:可以導(dǎo)航的區(qū)域
2. 使用網(wǎng)格導(dǎo)航組件實(shí)現(xiàn)跟隨物體位置移動(dòng)
搭建環(huán)境

- 平面障礙物
- 使用Off Mesh Link制作的路徑
- 樓梯
- 斜坡
- 斷層
- 洞口
3. 烘焙導(dǎo)航網(wǎng)格
-
打開(kāi)導(dǎo)航面板
-
選中要烘焙的地形對(duì)象
-
Navigation>>Object>>All,Navigation Static勾選
- Navigation>>Bake
- 調(diào)整半徑讓其盡可能多的包含地形對(duì)象
- 調(diào)整高度(可以進(jìn)入洞口)
- 調(diào)整最大坡度(可以上的坡度)
- 調(diào)整臺(tái)階高度(可以走上樓梯)
- 調(diào)整下落高度(可以從高出落下)
- 調(diào)整跳的距離(可以跳過(guò)斷層)
- 點(diǎn)擊Bake
-
-
烘焙之后Scene視圖中的效果,所有顯示藍(lán)色的網(wǎng)格是可以導(dǎo)航到的位置
-
設(shè)置能夠跳躍斷層
- 選中能夠跳躍的對(duì)象,Navigation>>Object>>All>>Generate OffMeshLinks勾選,然后進(jìn)入Bake面點(diǎn)擊Bake
-
烘焙之后Scene視圖中的效果,Plane出現(xiàn)了箭頭指向了另一頭的Plane
- 使用Off Mesh Link制作的路徑
- 創(chuàng)建一個(gè)Cube放在第一個(gè)Plane的邊緣,克隆一個(gè)放在第二個(gè)Plane的邊緣
- 在第一個(gè)Cube身上添加Off Mesh Link組件,把第一個(gè)Cube拖到組件的Start中,把第二個(gè)Cube拖到組件的End中,這樣就可以從第一個(gè)Plane的第一個(gè)Cube的位置到第二個(gè)Plane的第二個(gè)Cube的位置;中間的黑線就是Off Mesh Link制作的路徑

4. 創(chuàng)建角色和跟隨物體
-
創(chuàng)建一個(gè)膠囊體當(dāng)作小人
-
創(chuàng)建一個(gè)Cube當(dāng)作跟隨物體
5. 在角色身上添加Navigation Mesh Agent組件

6. 腳本
- 功能:讓角色導(dǎo)航到跟隨物體的位置
- 把腳本掛載到角色身上
- 把跟隨物體拖到腳本的實(shí)例對(duì)象上

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;//人工智能的命名空間
//按下鼠標(biāo)左鍵玩家跟隨移動(dòng)
//掛載對(duì)象:Player游戲?qū)ο?public class Test01 : MonoBehaviour
{
//玩家要到達(dá)的位置
public Transform TrCube;
//網(wǎng)格導(dǎo)航代理
private NavMeshAgent mNMA;
void Start()
{
//得到NavMeshAgent組件
mNMA = GetComponent<NavMeshAgent>();
}
void Update()
{
//到指定的位置(終點(diǎn)的位置)
//方法一:通過(guò)屬性
mNMA.destination = TrCube.position;
//方法二:通過(guò)方法
//mNMA.SetDestination(TrCube.position);
}
}
參考文章:Unity3D 官方文檔 NavMesh三個(gè)組件的翻譯與解釋 自動(dòng)尋路需要知道的細(xì)節(jié)







