[Unity]寻路导航
自動尋路
【Unity3D】自動尋路系統Navigation實現人物上樓梯、走斜坡、攀爬、跳躍 - 百度文庫
?、Navigation?板
 這?寫圖?描述
 Navigation?板中包括?個模塊
 Agents
 這?寫圖?描述
 這個是可以添加多個NabigationAgents可以?不同的Agents
 參數:
 Name:設置烘培Agents的名字
 Radius:烘培的半徑,也就是物體的烘培的半徑。這個值影響物體能通過的路徑的??
 越?,能??的路徑越?,邊緣區域越?
 Height: 具有代表性的物體的?度,可以通過的最低的空間?度。這個值越?,能通過的最??度越?。打個??就是,1m7的?能通過
 1m7的洞是正常的,你可以設置height為1m,就能通過1m的?度
 Step Height :梯?的?度,這個還是要看模型階梯的?度來設置
 Max Slope:烘培的最?的?度,就是坡度了
 Areas
 這?寫圖?描述
 這個是可以設置?動尋路烘培的層
 配合Nav Mesh Agents使?
 這?寫圖?描述
 Nav Mesh Agents->Area Mask->可以設置可以通過哪些層
 Bake
 這?寫圖?描述
 這個就是設置烘培參數的
 參數:
 Radius:具有代表性的物體半徑,半徑越??成的?格?積越?。
 Height:具有代表性的物體的?度。
 Max Slope:斜坡的坡度。
 Ste Height:臺階?度。
 Drop Height:允許最?的下落距離。
 Jump Distance:允許最?的跳躍距離。
 Min Region Area:?格?積?于該值則不?成導航?格。
 Height Mesh:勾選后會保存?度信息,同時會消耗?些性能和存儲空間。
 Object
 這?寫圖?描述
 這個是設置去烘培哪個對象,?如地形之類的,就是可以??的范圍路徑
 參數:
 Scene Filter:選擇場景中那些對象,可以選擇全部(All),地形(Terrains),有?格對象(Mesh Renderers)
 Navigation Static:可以烘培
 Generate OffMeshLinks:可以跳躍的地?
 兩種?成OffMeshLink的?法:
 第?種?成OffMeshLink的?法
 添加OffMeshLink組件
 在這?插?圖?描述
 參數:
 Start:設置起點
 End:設置終點
 兩者順序沒有關系
 Cost Override:這個參數還沒有研究
 BI Directional:同上
 Activated:同上
 Auto Update Position:同上
 Navigation Area:同上
 第?種?成OffMeshLink的?法
 在Navigation?板的Object欄??把OffMeshLink Generation選項打上勾
 這?寫圖?描述
 這?要說的?點是,是不是有的?把OffMeshLink Generation選項打上勾之后Back之后還是沒有出現OffMeshLink
 這?寫圖?描述
 這是因為你沒有設置Jump Distance的值
 這?寫圖?描述
 這個值越?,能跳的距離越遠,然后能跳的越?
 Navigation Area:表?是哪個Area,這個需要先設置,系統默認是Walkble、Jump、NotWalkble三種
 這個也要配合Nav Mesh Agent使?
 這?寫圖?描述
 ?、NavMeshAgent組件
 2.1 Agent Size
 Radius
 物體的半徑
 Height
 物體的?度,如果AgentHeight的值?于這個值,那么就不能通過
 Base Offset
 偏移值
 2.2 Steering
 Speed
 物體?動尋路的速度
 Angular Speed
 轉?的速度,就是轉彎的速度
 Acceleration
 加速度
 Stopping Distance
 物體停下來的距離,設置為0就是跟?標點的距離為0時停下來
 Auto Braking
 是否?動停下來
 2.3 Obstacle Avoidance
 Quality
 如果要防??群尋路的物體圍住?標點
 可以設置Quality為None,即可以讓尋路物體互相穿過
 Priority
 優先權
 2.4 Path Finding?動尋路
 Auto Traverse Off Mesh Link
 ?動跳躍鏈接
 Auto Repath
 ?動復制路徑
 Area Mask
 能通過的Maks層,這個可以配合Navigation組件中Areas(設置層的)使?
 三、NavMeshObstacle組件障礙物組件
 這?寫圖?描述
 如果想要在場景中,動態的放置障礙物,然后也不想在場景開始前就洪培好地形的話,就可以在物體上加上這個組件,然后設置好參數,將
 ?動尋路組件NavMeshAgent的尋路避讓優先級調??點
 Shape
 障礙物的模型,有Box和Capsule兩個選項,從單詞意思就可以看出來什么意思就不解釋了
 Center
 中?點,如果障礙模型的中?點不在模型的中?點上就可以做?些調整
 Size
 設置??
 Carve
 Move Threshold 模型 移動某個距離后進?烘焙
 Time To Stationary 指定模型在某個位置停??段時間 后 在進?烘焙
 Carve One Stationary 勾選后,模型移動時不會實時烘焙
 四、實例例?
 步驟?般是這樣的:
 1.在場景中擺放各種模型,包括地板,斜坡,?體,扶梯等
 2.為所有的模型加上Navigation Static和OffMeshLink Generatic(這個根據需要,例如地板與斜坡相連,斜坡就不需要添加
 OffMeshLink)
 3.特殊處理扶梯,需要?動添加Off Mesh Link,設置好開始點和結束點
 4.保存場景,烘焙場景
 例??:簡單尋路
 我們要實現?個功能:點擊場景中的?個位置,??可以?動尋路過去。??會繞過各種復雜的障礙,找到?條理論上”最短路徑“。
 步驟:
 1.創建地形
 2.添加??
 3.創建多個障礙物,盡量擺的復雜?點,來檢查Navmesh的可?性和效率。
 4.選中地形,在Navigation窗?中,設置Navigation Static
 5.依次選中障礙物,在avigation窗?中,設置Navigation Static
 7.Navigation窗?中,選擇Bake(烘焙)界?,點擊Bake按鈕,進程場景烘焙,就可以烘焙出尋路?格了
 8.為??添加NavMeshAgent組件。Component->Navigation->Nav Mesh Agent
 9.為??新增?個腳本PlayerController.cs,實現點擊?標,?動尋路功能
 代碼:
 using UnityEngine;
 using System.Collections;
 public class PlayerController : MonoBehaviour
 {
 ? ? private NavMeshAgent agent;
 ? ? void Start()
 ? ? {
 ? ? ? ? //獲取組件
 ? ? ? ? agent = GetComponent<NavMeshAgent>();
 ? ? }
 ? ? void Update()
 ? ? {
 ? ? ? ? //?標左鍵點擊
 ? ? ? ? if (Input.GetMouseButtonDown(0))
 ? ? ? ? {
 ? ? ? ? ? ? //攝像機到點擊位置的的射線
 ? ? ? ? ? ? Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 ? ? ? ? ? ? RaycastHit hit;
 ? ? ? ? ? ? if (Physics.Raycast(ray, out hit))
 ? ? ? ? ? ? {
 ? ? ? ? ? ? ? ? //判斷點擊的是否地形
 ? ? ? ? ? ? ? ? if (!hit.collider.name.Equals("Terrain"))
 ? ? ? ? ? ? ? ? {
 ? ? ? ? ? ? ? ? ? ? return;
 ? ? ? ? ? ? ? ? }
 ? ? ? ? ? ? ? ? //點擊位置坐標
 ? ? ? ? ? ? ? ? Vector3 point = hit.point;
 ? ? ? ? ? ? ? ? //轉向
 ? ? ? ? ? ? ? ? transform.LookAt(new Vector3(point.x, transform.position.y, point.z));
 ? ? ? ? ? ? ? ? //設置尋路的?標點
 ? ? ? ? ? ? ? ? agent.SetDestination(point);
 ? ? ? ? ? ? }
 ? ? ? ? }
 ? ? ? ? //播放動畫,判斷是否到達了?的地,播放空閑或者跑步動畫
 ? ? ? ? if (agent.remainingDistance == 0)
 ? ? ? ? {
 ? ? ? ? ? ? animation.Play("idle");
 ? ? ? ? }
 ? ? ? ? else
 ? ? ? ? {
 ? ? ? ? ? ? animation.Play("run");
 ? ? ? ? }
 ? ? }
 }
 例??:上下斜坡
 烘焙上下斜坡的問題
 這?寫圖?描述
 在?Unity的?動尋路系統的時候,如果?物不能實現按照規定到達?的地,有絕?的原因是烘焙尋路出現了問題,所以這是我們?先需要
 重視的地?。
 下?就是?開始我烘焙的尋路,?家可能發現問題了,就是在兩個紅圈的位置是沒有烘焙上的,并且區域很?,當?物尋路到這?的時候很
 容易卡在這?。
 這?寫圖?描述
 那就讓我們來設置烘焙的參數吧。
 這?寫圖?描述
 ?先來介紹?個各個參數的含義:
 Agent Radius:烘焙的半徑,其數值越?則烘焙效果越好;
 Agent Height:烘焙的?度,?物通過的?度;
 Max Slope:烘焙的最?坡度,?于這個坡度的?將不會烘焙;
 Step Height:烘焙的臺階?度,如果?度差?于設置值,將視為連接。
 烘焙參數設置
 所以我們將烘焙半徑調?點就可以解決這個問題了。
 我將烘焙半徑設置為0.1,烘焙效果如下圖,上坡和下邊的地?連接處沒有烘焙上的區域就很?啦。
 烘焙好的效果圖
 這?寫圖?描述
 斜坡?度和連接問題
 如果上坡的?度很?,?物也會卡在上坡中,我現在設置的上坡?度是40度。如果把?度設置為30度或者以下,?物就可以很順利的爬上
 斜坡啦。
 上坡?度很?
 這?寫圖?描述
 如果下坡的?度很?,?物就會直接跳下斜坡,我現在設置的下破的?度是50度。可以從圖中看到?物是直接跳下來的。如果把?度設置
 為40度或者以下,?物就可以很順利的下斜坡啦。
 下坡?度很?
 這?寫圖?描述
 還有就是斜坡與地?和站臺連接處的問題,它們的連接之間?定不能有空隙,否則?物也容易卡在空隙處。如下圖中,斜坡與站臺沒有完全
 連接上,有個很?的縫隙,即使尋路也烘焙得沒有問題,?物有時候也會卡在這個地?。
 斜坡連接處處理
 這?寫圖?描述
 ?物容易卡在尋路的邊緣處
 因為尋路就是解決的?物通過查找最短的路徑(在忽略消耗體?值前提下),并最終達到?的地的問題,所以在上下坡也經常會遇到?物會
 沿著斜坡?邊運動,這個就可能使?物卡在烘焙好的尋路邊緣處。
 我的解決辦法是設置中間?標物,讓其繞開尋路邊緣運動,這就需要設置?個中間?標,當?物到達?個?標的時候,然后向著下?個?標
 運動。
 從圖中可以看出設置了三個?標物,這樣?物就可以順利到達?標3啦。
 這?寫圖?描述
 代碼:
 [RequireComponent(typeof(NavMeshAgent))]
 public class NavigationTest : MonoBehaviour {
 ? ? public Transform targetOne;
 ? ? public Transform targetTwo;
 ? ? public Transform targetThree;
 ? ? private NavMeshAgent navAgent;
 ? ? private float distanceOne;
 ? ? private float distanceTwo;
 ? ? // Use this for initialization
 ? ? void Start () {
 ? ? ? ? navAgent = transform.GetComponent<NavMeshAgent>();
 ? ? ? ? navAgent.SetDestination(targetOne.position);
 ? ? }
 ? ? // Update is called once per frame
 ? ? void Update ()?
 ? ? {
 ? ? ? ? CheckReachTarget();
 ? ? }
 ? ? void CheckReachTarget()
 ? ? {
 ? ? ? ? distanceOne = Vector3.Distance(transform.position,targetOne.position);
 ? ? ? ? distanceTwo = Vector3.Distance(transform.position,targetTwo.position);
 ? ? ? ? if (distanceOne < 1f)
 ? ? ? ? {
 ? ? ? ? ? ? navAgent.SetDestination(targetTwo.position);
 ? ? ? ? }
 ? ? ? ? if (distanceTwo<1f)
 ? ? ? ? {
 ? ? ? ? ? ? navAgent.SetDestination(targetThree.position);
 ? ? ? ? }
 ? ? }
 }
 例?三:簡單的?動尋路
 1.在Scene中新建三個Cube,如下圖擺放。
 這?寫圖?描述
 2.選中上圖三個Cube,并在Inspector?板中選中為靜態(static)下拉選項的Navigation Static,如下圖。
 這?寫圖?描述
 3.依次選擇菜單欄中的Windows - Navigation ,打開后?板如下。
 這?寫圖?描述
 單擊該?板右下?的Bake按鈕,即可?成導航?格,下圖為已?成的導航?格。
 在這?插?圖?描述
 4.下?就可以讓?個運動體根據?個導航?格運動到?標位置。
 ?先新建?個Cube為?標位置,起名TargetCube。然后創建?個capsule(膠囊)運動體,為該膠囊掛在?個Nav Mesh
 Agent(Component - Navigation - Nav Mesh Agent);最后寫?個腳本就可以實現?動尋路了。腳本如下:
 using UnityEngine;
 using System.Collections;
 public class Run : MonoBehaviour {
 ? ? public Transform TargetObject = null;
 ? ? void Start () {
 ? ? ? ? if (TargetObject != null)
 ? ? ? ? {
 ? ? ? ? ? ? GetComponent<NavMeshAgent>().destination = TargetObject.position;
 ? ? ? ? }
 ? ? }?
 ? ? void Update () {
 ? ? }
 }
 腳本新建完成后掛載到膠囊體上,然后將TargetCube賦予給膠囊體的Run腳本,運?場景,如下圖,膠囊體會按照箭頭的?向運動到
 Cube位置。
 這?寫圖?描述
 這樣?個簡單的?動尋路就完成了,如果要更精細的尋路,或要實現上坡,鉆"橋洞"等,可根據下?介紹的相關參數進?調節。
 下?介紹Navigation組件和Nav Mesh Agent組件的相關參數。
 Navigation
 Object:物體參數?板
 Navigation Static:勾選后表?該對象參與導航?格的烘培。
 OffMeshLink Generation:勾選后可跳躍(Jump)導航?格和下落(Drop)。
 Bake:烘培參數?板  
 Radius:具有代表性的物體半徑,半徑越??成的?格?積越?。
 Height:具有代表性的物體的?度。
 Max Slope:斜坡的坡度。
 Ste Height:臺階?度。
 Drop Height:允許最?的下落距離。
 Jump Distance:允許最?的跳躍距離。
 Min Region Area:?格?積?于該值則不?成導航?格。
 Height Mesh:勾選后會保存?度信息,同時會消耗?些性能和存儲空間。
 Nav Mesh Agent:導航組建參數?板    
 Radius:物體的半徑
 Speed:物體的?進最?速度
 Acceleration:物體的?進加速度
 Augular Speed:?進過程中轉向時的?速度。
 Stopping Distance:離?標距離還有多遠時停?。
 Auto Traverse Off Mesh Link:是否采?默認?式度過鏈接路徑。
 Auto Repath:在?進某些原因中斷后是否重新開始尋路。
 Height:物體的?度。
 Base Offset:碰撞模型和實體模型之間的垂直偏移量。
 Obstacle Avoidance Type:障礙躲避的的表現登記,None選項為不躲避障礙,另外等級越?,躲避效果越好,同時消耗的性能越多。
 Avoidance Priority:躲避優先級。
 NavMesh Walkable:該物體可以?進的?格層掩碼。
 例?四:Navigation實現?低落差以及跳躍的做法
 在這?插?圖?描述
 在這?插?圖?描述
 不管是爬樓梯,還是跳躍,NavMesh都是通過了OffMeshLink來做的。創建OffMeshLink的?法有兩種,接下來會通過制作上?的例?
 來進?說明:
 這?寫圖?描述
 為了做這個例?,我們預先在場景??準備了?些物體:攝像機是必須的,?個作為地?的Plane,然后是F1——F5?個?低落差不?樣
 的臺階,L1和L2是樓梯模型, 控制?物主體man,還有移動的?標點target。
 其中man?上必須帶有NavMesh Agent組件,為了觀察?便在target?上帶了light組件。
 這?寫圖?描述
 按照上?節所講的,plane和F1——F5臺階在Navigation?板勾選Navigation Static選項,然后Bake,觀察Scene視窗,會發現已經?成
 了我們所要的NavMesh?格,現在我們可以像上?節那樣在plane上?給?物做尋路和移動了,但?物是不會爬樓梯的。
 這時候,我們找到L1樓梯,在樓梯的開始和結束的位置放置兩個點,這兩個點只需要拾取它的位移的,你可以?empty Gameobject來
 做,我這?為了便于觀察,就拿了cube來做。開始點命名為startPoint,結束點命名為endPoint。
 這?寫圖?描述
 注意:startPoint和endPoint的位置要稍微?所在的平???點點。
 接下來介紹第?種?成OffMeshLink的?法。選擇L1樓梯,然后在Component下拉選項中選擇Navigation——Off Mesh Link。
 這?寫圖?描述
 選擇后,OffMeshLink組件已經添加到了L1的?上,我們可以在Inspector?板看到:
 我們把剛才放置在場景??的startPoint和endPoint指定到OffmeshLink組件的Start和End位置,其他選項默認不改變
 這?寫圖?描述
 再次Bake
 這?寫圖?描述
 這?寫圖?描述
 現在我們發現,在scene?板??,在startPoint和endPoint之間?成了?條線,??向是從startPoint指向endPoint的。
 在這?插?圖?描述
 這時候,你應該可以通過移動?標點讓??開始爬樓梯了。但爬上去之后??暫時不能跳下來,如果把?標點移動到plane上,??會順著
 樓梯爬下來。
 我們使?同樣的?法對L2進??成OffMeshLink。這時候,??應該可以爬兩層樓梯了。到此第?個?標完成了。
 接下來我們進?第?個?標的制作,?先先來分析?下我們的場景:
 這?寫圖?描述
 我們希望?物能從2.5M的?度往下跳,超過2.5M?物就不能跳了,太?會有危險。然后橫向我們希望?物能跳過2?的溝。
 根據這個設定,我們的場景會是這樣的情況:L1和L2只能通過爬樓梯,L2和L3之間可以跳躍,L3——L5是可以往下跳的。
 于是,我們在Navigation?板??找到Bake欄,Drop Height(掉落?度)填2.5,Jump Distance(跳躍距離)填2,單位都是?
 這?寫圖?描述
 接下來介紹第?種?成OffMeshLink的?法:
 我們把L1——L5的物體選中,在Navigation?板的Object欄??把OffMeshLink Generation選項打上勾
 這?寫圖?描述
 再次Bake,回到scene視窗:
 這?寫圖?描述
 這時候,場景??會出現很多?的OffMeshLink,這是unity通過計算,把可以跳躍或者下落的地??動?成了OffMeshLink了。
 這時候,你應該已經可以通過移動?標點,讓??進?跳躍和下落了。
 進?到這?,我們的第?個?標也完成了。
 不過有些朋友可能會提出疑問,在做的過程中,假如沒有這個?兵的模型,?是??個膠囊體來代替?物的話,它爬樓梯和跳躍的時候好像
 是在?瞬間完成的,沒有?兵那個爬樓梯和跳躍動作的過程。如這樣:
 這?寫圖?描述
 這?寫圖?描述
 的確是這樣,因為默認的NaveMesh Agent組件上?是勾選了Auto Traverse Off Mesh Link(?動通過OffMeshLink)選項的。這樣的
 意思是?物只要到了OffMeshLink的開始點,就會?動的移動到OffMeshLink的結束點。
 這?寫圖?描述
 假如各位需要對越過OffMeshLink時候進???的控制,是需要另外寫腳本的。我這?簡單的介紹?下?法,有興趣的朋友可以??試
 試。
 ?先各位最好有?狀態來控制??的概念。?如?物可以分為站?、?路、跑步、上下樓梯、橫向跳躍和往下掉落?種狀態,針對
 NavMesh來說,?物簡單的可以分為站?、正常的NavMesh尋路,和通過OffMeshLink移動?種狀態。
 先把 Auto Traverse Off Mesh Link選項取消。
 然后,當?物在通過OffMeshLink移動的狀態(可以?NavMeshAgent.isOnOffMeshLink來判斷),獲取到當前通過的
 OffMeshLink:
 OffMeshLinkData link = NavMeshAgent.currentOffMeshLinkData;
 這樣你就能獲取到link的開始點和結束點的坐標(link.startPos和link.endPos),這時候你的?物就可以?最簡單的Vector3.Lerp來進?
 移動,當?物的位移到達了結束點的坐標,?物的OffMeshLink移動狀態就可以結束,?重新變回正常尋路或者站?的狀態了。在這個
 Vector3.Lerp的過程中,你可以隨意的控制?物的爬?或者跳躍的動作。
 例?五:?動尋路Navmesh之跳躍,攀爬,斜坡
 步驟:
 1.在場景中擺放各種模型,包括地板,斜坡,?體,扶梯等
 2.為所有的模型加上Navigation Static和OffMeshLink Generatic(這個根據需要,例如地板與斜坡相連,斜坡就不需要添加
 OffMeshLink)
 3.特殊處理扶梯,需要?動添加Off Mesh Link,設置好開始點和結束點
 4.保存場景,烘焙場景
 5.添加??模型,為其加Nav Mesh Agent組件
 6.為??添加?個新腳本,AgentLocomotion.cs,?來處理?動尋路,已經??動畫變換。代碼?較長,?家可以結合注釋來理解
 代碼:
 using UnityEngine; ?
 using System.Collections; ?
 public class AgentLocomotion : MonoBehaviour ?
 { ?
 ? ? private Vector3 target;//?標位置
 ? ? private NavMeshAgent agent; ?
 ? ? private Animation anim;//動畫
 ? ? private string locoState = "Locomotion_Stand"; ?
 ? ? private Vector3 linkStart;//OffMeshLink的開始點
 ? ? private Vector3 linkEnd;//OffMeshLink的結束點
 ? ? private Quaternion linkRotate;//OffMeshLink的旋轉
 ? ? private bool begin;//是否開始尋路
 ? ? // Use this for initialization ?
 ? ? void Start() ?
 ? ? { ?
 ? ? ? ? agent = GetComponent<NavMeshAgent>(); ?
 ? ? ? ? //?動移動并關閉OffMeshLinks,即在兩個隔離障礙物直接?成的OffMeshLink,agent不會?動越過
 ? ? ? ? agent.autoTraverseOffMeshLink = false; ?
 ? ? ? ? //創建動畫
 ? ? ? ? AnimationSetup(); ?
 ? ? ? ? //起?個協程,處理動畫狀態機
 ? ? ? ? StartCoroutine(AnimationStateMachine()); ?
 ? ? } ?
 ? ? void Update() ?
 ? ? { ?
 ? ? ? ? //?標左鍵點擊
 ? ? ? ? if (Input.GetMouseButtonDown(0)) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? //攝像機到點擊位置的的射線
 ? ? ? ? ? ? Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); ?
 ? ? ? ? ? ? RaycastHit hit; ?
 ? ? ? ? ? ? if (Physics.Raycast(ray, out hit)) ?
 ? ? ? ? ? ? { ?
 ? ? ? ? ? ? ? ? //判斷點擊的是否地形
 ? ? ? ? ? ? ? ? if (hit.collider.tag.Equals("Obstacle")) ?
 ? ? ? ? ? ? ? ? { ?
 ? ? ? ? ? ? ? ? ? ? begin = true; ?
 ? ? ? ? ? ? ? ? ? ? //點擊位置坐標
 ? ? ? ? ? ? ? ? ? ? target = hit.point; ?
 ? ? ? ? ? ? ? ? } ?
 ? ? ? ? ? ? } ?
 ? ? ? ? } ?
 ? ? ? ? //每?幀,設置?標點
 ? ? ? ? if (begin) ?
 ? ? ? ? if (begin) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? agent.SetDestination(target); ?
 ? ? ? ? } ?
 ? ? } ?
 ? ? IEnumerator AnimationStateMachine() ?
 ? ? { ?
 ? ? ? ? //根據locoState不同的狀態來處理,調?相關的函數
 ? ? ? ? while (Application.isPlaying) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? yield return StartCoroutine(locoState); ?
 ? ? ? ? } ?
 ? ? } ?
 ? ? //站?
 ? ? IEnumerator Locomotion_Stand() ?
 ? ? { ?
 ? ? ? ? do ?
 ? ? ? ? { ?
 ? ? ? ? ? ? UpdateAnimationBlend(); ?
 ? ? ? ? ? ? yield return new WaitForSeconds(0); ?
 ? ? ? ? } while (agent.remainingDistance == 0); ?
 ? ? ? ? //未到達?標點,轉到下?個狀態Locomotion_Move ?
 ? ? ? ? locoState = "Locomotion_Move"; ?
 ? ? ? ? yield return null; ?
 ? ? } ?
 ? ? IEnumerator Locomotion_Move() ?
 ? ? { ?
 ? ? ? ? do ?
 ? ? ? ? { ?
 ? ? ? ? ? ? UpdateAnimationBlend(); ?
 ? ? ? ? ? ? yield return new WaitForSeconds(0); ?
 ? ? ? ? ? ? //??處于OffMeshLink,根據不同的地點,選擇不同動畫
 ? ? ? ? ? ? if (agent.isOnOffMeshLink) ?
 ? ? ? ? ? ? { ?
 ? ? ? ? ? ? ? ? locoState = SelectLinkAnimation(); ?
 ? ? ? ? ? ? ? ? return (true); ?
 ? ? ? ? ? ? } ?
 ? ? ? ? } while (agent.remainingDistance != 0); ?
 ? ? ? ? //已經到達?標點,狀態轉為Stand ?
 ? ? ? ? locoState = "Locomotion_Stand"; ?
 ? ? ? ? yield return null; ?
 ? ? } ?
 ? ? IEnumerator Locomotion_Jump() ?
 ? ? { ?
 ? ? ? ? //播放跳躍動畫
 ? ? ? ? string linkAnim = "RunJump"; ?
 ? ? ? ? Vector3 posStart = transform.position; ?
 ? ? ? ? agent.Stop(true); ?
 ? ? ? ? anim.CrossFade(linkAnim, 0.1f, PlayMode.StopAll); ?
 ? ? ? ? transform.rotation = linkRotate; ?
 ? ? ? ? do ?
 ? ? ? ? { ?
 ? ? ? ? ? ? //計算新的位置
 ? ? ? ? ? ? float tlerp = anim[linkAnim].normalizedTime; ?
 ? ? ? ? ? ? Vector3 newPos = Vector3.Lerp(posStart, linkEnd, tlerp); ?
 ? ? ? ? ? ? newPos.y += 0.4f * Mathf.Sin(3.14159f * tlerp); ?
 ? ? ? ? ? ? transform.position = newPos; ?
 ? ? ? ? ? ? yield return new WaitForSeconds(0); ?
 ? ? ? ? } while (anim[linkAnim].normalizedTime < 1); ?
 ? ? ? ? } while (anim[linkAnim].normalizedTime < 1); ?
 ? ? ? ? //動畫恢復到Idle ?
 ? ? ? ? anim.Play("Idle"); ?
 ? ? ? ? agent.CompleteOffMeshLink(); ?
 ? ? ? ? agent.Resume(); ?
 ? ? ? ? //下?個狀態為Stand ?
 ? ? ? ? transform.position = linkEnd; ?
 ? ? ? ? locoState = "Locomotion_Stand"; ?
 ? ? ? ? yield return null; ?
 ? ? } ?
 ? ? //梯?
 ? ? IEnumerator Locomotion_Ladder() ?
 ? ? { ?
 ? ? ? ? //梯?的中?位置
 ? ? ? ? Vector3 linkCenter = (linkStart + linkEnd) * 0.5f; ?
 ? ? ? ? string linkAnim; ?
 ? ? ? ? //判斷是在梯?上還是梯?下
 ? ? ? ? if (transform.position.y > linkCenter.y) ?
 ? ? ? ? ? ? linkAnim = "Ladder Down"; ?
 ? ? ? ? else ?
 ? ? ? ? ? ? linkAnim = "Ladder Up"; ?
 ? ? ? ? agent.Stop(true); ?
 ? ? ? ? Quaternion startRot = transform.rotation; ?
 ? ? ? ? Vector3 startPos = transform.position; ?
 ? ? ? ? float blendTime = 0.2f; ?
 ? ? ? ? float tblend = 0f; ?
 ? ? ? ? //??的位置插值變化(0.2內變化)
 ? ? ? ? do ?
 ? ? ? ? { ?
 ? ? ? ? ? ? transform.position = Vector3.Lerp(startPos, linkStart, tblend / blendTime); ?
 ? ? ? ? ? ? transform.rotation = Quaternion.Lerp(startRot, linkRotate, tblend / blendTime); ?
 ? ? ? ? ? ? yield return new WaitForSeconds(0); ?
 ? ? ? ? ? ? tblend += Time.deltaTime; ?
 ? ? ? ? } while (tblend < blendTime); ?
 ? ? ? ? //設置位置
 ? ? ? ? transform.position = linkStart; ?
 ? ? ? ? //播放動畫
 ? ? ? ? anim.CrossFade(linkAnim, 0.1f, PlayMode.StopAll); ?
 ? ? ? ? agent.ActivateCurrentOffMeshLink(false); ?
 ? ? ? ? //等待動畫結束
 ? ? ? ? do ?
 ? ? ? ? { ?
 ? ? ? ? ? ? yield return new WaitForSeconds(0); ?
 ? ? ? ? } while (anim[linkAnim].normalizedTime < 1); ?
 ? ? ? ? agent.ActivateCurrentOffMeshLink(true); ?
 ? ? ? ? //恢復Idle狀態
 ? ? ? ? anim.Play("Idle"); ?
 ? ? ? ? transform.position = linkEnd; ?
 ? ? ? ? agent.CompleteOffMeshLink(); ?
 ? ? ? ? agent.Resume(); ?
 ? ? ? ? //下?個狀態Stand ?
 ? ? ? ? locoState = "Locomotion_Stand"; ?
 ? ? ? ? yield return null; ?
 ? ? } ?
 ? ? private string SelectLinkAnimation() ?
 ? ? { ?
 ? ? ? ? //獲得當前的OffMeshLink數據
 ? ? ? ? OffMeshLinkData link = agent.currentOffMeshLinkData; ?
 ? ? ? ? //計算??當前是在link的開始點還是結束點(因為OffMeshLink是雙向的)
 ? ? ? ? float distS = (transform.position - link.startPos).magnitude; ?
 ? ? ? ? float distE = (transform.position - link.endPos).magnitude; ?
 ? ? ? ? float distE = (transform.position - link.endPos).magnitude; ?
 ? ? ? ? if (distS < distE) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? linkStart = link.startPos; ?
 ? ? ? ? ? ? linkEnd = link.endPos; ?
 ? ? ? ? } ?
 ? ? ? ? else ?
 ? ? ? ? { ?
 ? ? ? ? ? ? linkStart = link.endPos; ?
 ? ? ? ? ? ? linkEnd = link.startPos; ?
 ? ? ? ? } ?
 ? ? ? ? //OffMeshLink的?向
 ? ? ? ? Vector3 alignDir = linkEnd - linkStart; ?
 ? ? ? ? //忽略y軸
 ? ? ? ? alignDir.y = 0; ?
 ? ? ? ? //計算旋轉?度
 ? ? ? ? linkRotate = Quaternion.LookRotation(alignDir); ?
 ? ? ? ? //判斷OffMeshLink是?動的(樓梯)還是?動?成的(跳躍)
 ? ? ? ? if (link.linkType == OffMeshLinkType.LinkTypeManual) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? return ("Locomotion_Ladder"); ?
 ? ? ? ? } ?
 ? ? ? ? else ?
 ? ? ? ? { ?
 ? ? ? ? ? ? return ("Locomotion_Jump"); ?
 ? ? ? ? } ?
 ? ? } ?
 ? ? private void AnimationSetup() ?
 ? ? { ?
 ? ? ? ? anim = GetComponent<Animation>(); ?
 ? ? ? ? // 把walk和run動畫放到同?層,然后同步他們的速度。
 ? ? ? ? anim["Walk"].layer = 1; ?
 ? ? ? ? anim["Run"].layer = 1; ?
 ? ? ? ? anim.SyncLayer(1); ?
 ? ? ? ? //設置“跳躍”,“爬樓梯”,“下樓梯”的動畫模式和速度
 ? ? ? ? anim["RunJump"].wrapMode = WrapMode.ClampForever; ?
 ? ? ? ? anim["RunJump"].speed = 2; ?
 ? ? ? ? anim["Ladder Up"].wrapMode = WrapMode.ClampForever; ?
 ? ? ? ? anim["Ladder Up"].speed = 2; ?
 ? ? ? ? anim["Ladder Down"].wrapMode = WrapMode.ClampForever; ?
 ? ? ? ? anim["Ladder Down"].speed = 2; ?
 ? ? ? ? //初始化動畫狀態為Idle ?
 ? ? ? ? anim.CrossFade("Idle", 0.1f, PlayMode.StopAll); ?
 ? ? } ?
 ? ? //更新動畫融合
 ? ? private void UpdateAnimationBlend() ?
 ? ? { ?
 ? ? ? ? //??速度
 ? ? ? ? float walkAnimationSpeed = 1.5f; ?
 ? ? ? ? //奔跑速度
 ? ? ? ? float runAnimationSpeed = 4.0f; ?
 ? ? ? ? //速度閥值(idle和walk的臨界點)
 ? ? ? ? float speedThreshold = 0.1f; ?
 ? ? ? ? //速度,只考慮x和z ?
 ? ? ? ? Vector3 velocityXZ = new Vector3(agent.velocity.x, 0.0f, agent.velocity.z); ?
 ? ? ? ? //速度值
 ? ? ? ? float speed = velocityXZ.magnitude; ?
 ? ? ? ? //設置Run動畫的速度
 ? ? ? ? anim["Run"].speed = speed / runAnimationSpeed; ?
 ? ? ? ? anim["Run"].speed = speed / runAnimationSpeed; ?
 ? ? ? ? //設置Walk動畫的速度
 ? ? ? ? anim["Walk"].speed = speed / walkAnimationSpeed; ?
 ? ? ? ? //根據agent的速度??,確定animation的播放狀態
 ? ? ? ? if (speed > (walkAnimationSpeed + runAnimationSpeed) / 2) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? anim.CrossFade("Run"); ?
 ? ? ? ? } ?
 ? ? ? ? else if (speed > speedThreshold) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? anim.CrossFade("Walk"); ?
 ? ? ? ? } ?
 ? ? ? ? else ?
 ? ? ? ? { ?
 ? ? ? ? ? ? anim.CrossFade("Idle", 0.1f, PlayMode.StopAll); ?
 ? ? ? ? } ?
 ? ? } ?
 } ?
 效果圖:
 點擊任何?個地點,??都可以?動尋路過去。中間可能經過不同的障礙物,我們可以看到??如我們所預料的?樣,可以跳躍下來,可以
 爬樓梯,最終到達?標點。
 這?寫圖?描述
 源碼:
 例?六:?動尋路Navmesh之?級主題
 隔離層?動?成尋路?格
 1.創建Plane實例P1,P2,兩者之間出現?條鴻溝。直接控制??位移是?法通過的。
 2.打開Navigation窗?,分別選中P1,P2,分別設置Navigation Static 和OffMeshLink Generatic
 這?寫圖?描述
 3.保存場景,點擊場景烘焙按鈕Bake。結束后我們可以看到P1,P2除了???產尋路?格外,它們直接還?成了連接紐帶。
 4.添加??模型Solder,為其添加NavMeshAgent(Component->Navigation->NavMeshAgent)
 5.給Solder添加PlayerController腳本
 代碼:
 using UnityEngine; ?
 using System.Collections; ?
 public class PlayerController : MonoBehaviour ?
 { ?
 ? ? private NavMeshAgent agent; ?
 ? ? public bool setAgentWalkMask;//是否需要動態修改尋路層,在scene4的實例中要?到
 ? ? void Start() ?
 ? ? { ?
 ? ? ? ? //獲取尋路組件
 ? ? ? ? agent = GetComponent<NavMeshAgent>(); ?
 ? ? } ?
 ? ? void Update() ?
 ? ? { ?
 ? ? ? ? //?標左鍵點擊
 ? ? ? ? if (Input.GetMouseButtonDown(0)) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? //攝像機到點擊位置的的射線
 ? ? ? ? ? ? Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); ?
 ? ? ? ? ? ? RaycastHit hit; ?
 ? ? ? ? ? ? if (Physics.Raycast(ray, out hit)) ?
 ? ? ? ? ? ? { ?
 ? ? ? ? ? ? ? ? //判斷點擊的是否地形
 ? ? ? ? ? ? ? ? if (!hit.collider.tag.Equals("Plane")) ?
 ? ? ? ? ? ? ? ? { ?
 ? ? ? ? ? ? ? ? ? ? return; ?
 ? ? ? ? ? ? ? ? } ?
 ? ? ? ? ? ? ? ? //點擊位置坐標
 ? ? ? ? ? ? ? ? Vector3 point = hit.point; ?
 ? ? ? ? ? ? ? ? //轉向
 ? ? ? ? ? ? ? ? transform.LookAt(new Vector3(point.x, transform.position.y, point.z)); ?
 ? ? ? ? ? ? ? ? //設置尋路的?標點
 ? ? ? ? ? ? ? ? agent.SetDestination(point); ?
 ? ? ? ? ? ? } ?
 ? ? ? ? } ?
 ? ? ? ? //播放動畫
 ? ? ? ? if (agent.remainingDistance == 0) ?
 ? ? ? ? { ?
 ? ? ? ? ? ? animation.Play("Idle"); ?
 ? ? ? ? } ?
 ? ? ? ? else ?
 ? ? ? ? { ?
 ? ? ? ? ? ? animation.Play("Run"); ?
 ? ? ? ? } ?
 ? ? } ?
 } ?
 5.點擊任意的位置,可以看到??都能?動尋路過去
 效果圖
 這?寫圖?描述
 ?動指定尋路?格?向
 1.將P1,P2的OffMeshLink Generatic去除
 2.在P1上新建?個空的GameObject Start,P2上新建?個空的GameObject End
 3.選中start,為它添加Off Mesh Link組件 Component->Navigation->OffMeshLink
 4.設置Off Mesh Link組件的屬性,Start Point 為 start,End Point為end
 5.烘焙場景。我們可以看到有?條紐帶從start指向end
 點擊地圖,可以看到??如果要跨越P1和P2,?定是沿著我們?動創建的路徑
 這?寫圖?描述
 導航?格障礙物 Navmesh Obstacle
 之前我們都是?固定的物體作為障礙物,然后烘焙場景。Unity還提供了動態的障礙物。任何?個GameObject都可以添加Navmesh
 Obstacle組件,變成?個障礙物。具體步驟是Component->Navigation->Navmesh Obstacle.它有兩個屬性:半徑和?度,可以設置跟
 你的物品差不多的體積??。
 尋路?格層的應?
 1.新建P1,P2,P3,P4等4個Plane,具體擺設形狀見效果圖
 2.在Navigation窗?中,添加兩個層Layers:Blue層和Red層
 3.P1,P2的Navigation Layer設置為Default,P4的Navigation層設置為Red,P3設置為Blue
 4.添加兩個??,設置他們的NavMeshAgent尋路層(NavMesh Walkable)。?個將Red層去掉,?個將Blue層去掉
 5.點擊P2的坐標,可以看到他們沿著不同的路徑去?標點,?個?上層路線,?個?下層路線了。
 效果圖
 這?寫圖?描述
 動態改變尋路?格層
 1.在scene3.unity基礎上做?下修改。只保留?個??
 2.新增兩個按鈕,“?上層”和“?下層”,在游戲運?時,可以改變Agent的尋路層。
 代碼:
 //動態設置尋路路徑層
 ?void OnGUI() ?
 ? ?{ ?
 ? ? ? ?if (!setAgentWalkMask) ?
 ? ? ? ?{ ?
 ? ? ? ? ? ?return; ?
 ? ? ? ?} ?
 ? ? ? ?if (GUI.Button(new Rect(0, 0, 100, 50), "?下層")) ?
 ? ? ? ?{ ?
 ? ? ? ? ? ?agent.walkableMask = 65; ?
 ? ? ? ?} ?
 ? ? ? ?if (GUI.Button(new Rect(0, 100, 100, 50), "?上層")) ?
 ? ? ? ?{ ?
 ? ? ? ? ? ?agent.walkableMask = 129; ?
 ? ? ? ?} ?
 ? ?} ?
 3.重新點擊尋路,可以看到,選擇不同的尋路層,??的尋路路徑也不同
 這?寫圖?描述
 看到代碼中的agent.walkableMask = 65和129,?家會?較迷惑,其實尋路層每?層都是2的冪,見下圖
 這?寫圖?描述
 所以上層的mask = Default(1)+Blue(128) = 129,下層的mak = Default(1)+Red(64) = 65
 例?七:Navigation烘焙
 Building a NavMesh
 在Unity中,NavMesh 的?成操作需要Navigation窗?(在Window> Navigation)
 在你的場景中構建NavMesh只需要4個步驟:
 這?寫圖?描述
 在這?插?圖?描述
 選擇場景中需要?成尋路的?何體-可??表?和障礙物。
 在NavMesh?板中選擇需要烘焙尋路的物體,檢測是否勾選Navigation Static.
 根據你的agent??來調整bake ?板的設置。
 Agent Radius : agent可以距離墻體 ,窗戶或邊緣多近的距離。
 Agent Height : agent可以通過的最低的空間?度。
 Max Slope : agent可以直接??上去的最?坡度。
 Step Height: agent可以踩上(?上)的障礙物最??度。
 點擊bake按鈕烘焙NavMesh。
 當你的Navigation窗?打開并且可見時,烘焙的NavMesh結果在場景中會以藍?的覆蓋層在物體的?何體表?顯?。
 這?寫圖?描述
 烘焙完成后,您將在與NavMesh所屬場景同名的?件夾中找到?個NavMesh資產?件。例如,如果在Assets?件夾中有?個名為First
 Level的場景,NavMesh將位于 Assets > First Level > NavMesh.asset.當烘焙結束后,你可以找到?個名字和你的場景名?樣的?件
 夾,??有?個NavMesh的資源?件,是屬于這個場景的NavMesh。
 讓物體可烘焙的其他?法
 這?寫圖?描述
 直接選擇物體在Inspector?板頂部的Static 菜單,你可以直接選擇Navigation Static,?不?再打開Navigation 窗?。
 NavMesh烘焙的?級設置
 最?區域?積
 這?寫圖?描述
 這?寫圖?描述
 Min Region Area 允許你剔除掉?的?連接NavMesh區域,當NavMesh區域?于指定值時將被剔除。
 請注意:有些區域可能?法被移除,盡管有Min Region Area 的設置,原因是NavMesh的構建是?個個的?格并?構建。當?個區域橫跨
 兩個?格將不會被移除,因為區域修剪過程中?法獲取到周圍的?格。
 Voxel Size ?體像素尺?
 Manual voxel size :允許你改變烘焙操作過程中的精確性。
 Navigation在構建尋路?格過程中,第?遍會把場景光柵化為體素,然后提取可??區域,最后可??區域會烘焙成?格。因此體素尺?
 Voxel Size的決定了尋路?格烘焙的精準性。
 提?:默認的體素設置最好的權衡了準確性和烘焙速度。在烘焙場景尋路的過程中,體素的增加會造成4x倍的內存消耗和4x倍的時間消
 耗。因此通常,你不需要??去設置Voxel Size。
 這?寫圖?描述
 Smaller Agent Radius
 系統烘焙尋路是也會減?voxel size。如果你的agent尺?保持不變,可能不需要增加NavMesh的構建分辨率。
 更簡單的?法如下所?:
 設置你的半徑為真實agent半徑
 打開Manual Voxel Size,這會保持當前的voxel的??并且凍結它。
 ?為的將你的Agent Radius設置?,因為你已經勾選了Manual Voxel Size ,voxel size將不會改變。
 Height mesh : 允許你為??提供更精準的位置。
 這?寫圖?描述
 導航時,NavMesh代理被約束在NavMesh的表?。由于NavMesh是可步?空間的近似,所以在構建NavMesh時,?些特性會被平均化。
 例如,樓梯可能在NavMesh中顯?為?個斜坡。如果你的游戲需要準確的位置代理,你應該啟??度?格建設時,你烤NavMesh。該設置
 可以在導航窗?的?級設置中找到。注意,建筑?度?格將占?內存和處理在運?時,它將需要更長的時間來烘烤NavMesh。
 盡管普通的NavMesh 已經可以很好的運?,但是由于NavMesh只是?個近似的可??的空間,只保持了?些均衡的特性,如果你的游戲
 agent需要更精準的??位置,你可以啟??度?格Height Mesh,
 注意:?度?格Height Mesh將占?你“運?時”的內存和cpu,并且需要更多的烘焙時間。
 結束。。。
 這篇?章吸取了很多?的精華,有什么不對的地?希望都可以私信我。
 ?
總結
以上是生活随笔為你收集整理的[Unity]寻路导航的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 定制Github日历库EPCalenda
 - 下一篇: FOC电机ST系列处理器使用的基础知识