Unity里面的自動尋路(二)-創(chuàng)新互聯(lián)

    接著我的 上一篇自動尋路文章,這一次我們就來學(xué)習(xí)一下與自動尋路有關(guān)的組件吧。Unity中與自動尋路相關(guān)的組件主要有兩個:NavMeshAgent (  又稱導(dǎo)航網(wǎng)格代理 ),Off Mesh Link( 分離網(wǎng)格鏈接 )。這兩個組件的作用與使用范圍是不同的,我們唯一可以確定的是我們必須烘焙地形,產(chǎn)生NavMesh(導(dǎo)航網(wǎng)格)。因為導(dǎo)航網(wǎng)格決定我們的角色(帶有導(dǎo)航網(wǎng)格代理的角色)活動的范圍。NavMeshAgent組件需要附著尋路的角色身上,比如怪物,而OffMeshLink這個組件主要是用來構(gòu)造尋路角色的尋路路徑的某個部分,比如我們有時需要怪物在尋路過程中從一個固定的地方移動到另一個固定的地方,這將會在我下面的例子中清楚的看到。好了,甭廢話了,讓我們開始吧!
      首先,我們先來了解一下NavMeshAgent組件,這個組件是unity3d提供的尋路系統(tǒng)的核心組件。官方是這樣解釋的:The NavMeshAgent component is connection with pathfinding,and is the place to put information about how this agent navigates the NavMesh 。意思大致是這樣的:NavMeshAgent組件是關(guān)于尋路的,它是一個用來存放代理周游導(dǎo)航網(wǎng)格的路徑信息的平臺。那么代理又是什么呢?原來,角色的移動是要依靠代理來做的,每一個附著這個組件在尋路的過程中都是利用代理進行的,這也就是這個組件為什么叫導(dǎo)航網(wǎng)格代理的原因。每一個你需要讓它具有自動尋路功能的角色必須要附著這個組件,除非你利用其它的尋路算法,但那樣做實在是太復(fù)雜了,因為考慮的情況太多了,然而Unity為我們提供了這樣一個組件,我們?yōu)樯恫挥媚??我們先來舉一個例子吧,這樣學(xué)起來也好理解一些。
      我接著我上一篇文章中的工程,新建了一個Scene,給了它一個名字:TestNavgation2。然后這個場景里面也需要一個地面,我還是用Cube來做。這次我先向這個平面上建一個Spere,重命名為Hero,并且給它加上一個NavMeshAgent組件,方法:Unity菜單,Component->Navgation->NavMeshAgent。給Hero上個顏色就像下面截圖一樣:



選中Hero,在Inspector下,我們可以看到NavMeshAgent組件的各個屬性:



這幾個屬性我簡單的解釋一下:
Radius:導(dǎo)航代理的半徑,我們可以適當(dāng)?shù)恼{(diào)節(jié)一下這個值

Speed :這個屬性代表這個導(dǎo)航網(wǎng)格代理尋路時可以達到的大速率

Acceleration :加速度,表示代理的速度從0加速到Speed時的大的加速度

Angular Speed :高的角速度

Stopping distance : 制動距離,當(dāng)代理據(jù)目的地的距離小于這個值時開始減速

Auto Traverse OffMesh Link :自動移動并關(guān)閉OffMeshLinks,這個選項對于我們利用程序來操縱后面我要介紹的OffMeshLink很關(guān)鍵,

Auto Repath  自動重新尋路,如果發(fā)現(xiàn)現(xiàn)有路徑已失效,那么它將獲得新的路徑,這個選項我們一般將其勾選上

Height  : 導(dǎo)航代理的高度。

Base Offset : 基本偏移,我們可以通過調(diào)整這個變量來調(diào)整代理自身的包圍盒

Obstacle Avoidace Type  : 代理躲避的水平,一般我們選默認(rèn)的High Quality就行了

NavMesh Walkable :導(dǎo)航網(wǎng)格代理可以通過的網(wǎng)格層類型
好了這些屬性我們基本上知道了一點,但要真正理解它,我們還有很長的路要走。我們到頭來是要用腳本來控制尋路的,也就是說我們必須掌握NavMeshAgent這個類,還是老辦法,看文檔吧,記住,文檔我們必須看,這是我們學(xué)習(xí)新東西必須做的,那些出視頻,出書的沒一個不是從看文檔開始的。
      我們看NavMeshAgent這個類,Unity菜單:help->Scripting Reference 。我們找到這個類,發(fā)現(xiàn)里面的變量和方法還不少呢。這次我不可能將其全部講解到 , 因為有些我自己都沒用過,所以我只講解我們常用的:
NavMeshAgent(導(dǎo)航網(wǎng)格代理組件所對應(yīng)的類)
假使我們的主角身上添加了一個導(dǎo)航網(wǎng)格組件,我們一般在腳本中這樣定義NavMeshAgent類型的成員變量:
private NavMeshAgent nma ;
并在Start或Awake函數(shù)中實例化它:
nma = gameObject.GetComponent<NavMeshAgent>();
重要變量:
1.destination
我們可以這樣對導(dǎo)航網(wǎng)格代理設(shè)置目的地:
nma.destination = Vector3類型的值。相當(dāng)于nma.SetDestination( Vector3類型的值 )

2.stoppingDistance
這個與Inspector面板中的Stopping Distance對應(yīng),一下再不涉及與Inspector面板中的屬性對應(yīng)的變量

3.velocity
導(dǎo)航網(wǎng)格代理周游時的實時速度,非常重要

4.nextPosion
顧名思義,也就是下一個位置,在Update函數(shù)中打印這個屬性,你會發(fā)現(xiàn)打印出的結(jié)果與這個導(dǎo)航網(wǎng)格代理周游過的路徑一致

5.steeringTarget(只讀)
這個屬性是相當(dāng)重要的,它指的是導(dǎo)航網(wǎng)格代理在導(dǎo)航網(wǎng)格中周游時所經(jīng)過的拐點,這對于制作尋路網(wǎng)游同步角色的Transform是相當(dāng)重要的,因為導(dǎo)航網(wǎng)格的尋路路線是直線,我們只需將其尋路的拐點與旋轉(zhuǎn)角度告訴給服務(wù)器端,有服務(wù)器端廣播出去,然后再寫一個執(zhí)行Transform同步的腳本(是特制的)綁定在非角色玩家身上就可以了。

6.desiredVelocity(只讀)
這個屬性說實話我用的不多,指的是導(dǎo)航網(wǎng)格代理的期望速度,與其當(dāng)前速度不是等價的。

7.remainingDistance( 只讀 )
導(dǎo)航網(wǎng)格代理離目的地還剩的距離,如果其值為0,那么代理已經(jīng)到達了目的地了,所以我們可一個這樣判斷一個導(dǎo)航網(wǎng)格代理是否到達了目的地:
if( nma.remainingDistance == 0 ){
//執(zhí)行行為

}

8.isOnOffMeshLink
導(dǎo)航網(wǎng)格代理當(dāng)前的位置是否位于OffMeshLink,因為這個牽扯到了另一個組件,我會在后面說的

重要方法:
1.SetDestination( Vector3 v )
設(shè)置目的地,與nma.destination = v一樣的,你想怎么用都行,只是這個函數(shù)在設(shè)置目的地成功后返回***e,否則返回false,就只比調(diào)用屬性多了一個返回值

2.ActivateCurrentOffMeshLink( bool activated )
返回值為空
與OffMeshLink有關(guān),當(dāng)activated為***e激活OffMeshLink,后面會講到的

3.CompleteOffMeshLink ()
讓導(dǎo)航網(wǎng)格代理完成在OffMeshLink上的周游,后面會講的

4.Move( Vector3 v )
讓導(dǎo)航網(wǎng)格代理朝向量v的世界坐標(biāo)系方向平移v的長度

5.Stop()
讓導(dǎo)航網(wǎng)格代理停止尋路,但此尋路狀態(tài)可以靠下面一個函數(shù)恢復(fù)到尋路狀態(tài),并且目的地也與上次一樣

6.Resume()
恢復(fù)尋路狀態(tài),此時角色會在上一次執(zhí)行了Stop函數(shù)停下來后恢復(fù)當(dāng)時的狀態(tài),目的地為上一次的目的地

這8個屬性與Inspector面板上的各個屬性并且和這6個函數(shù)我們一定要好熟練掌握,這關(guān)系到我們是否能熟練書寫尋路腳本。還有一些函數(shù)我這里沒有介紹,就留著讀者自己研究研究吧。
      此刻我相信讀者對這個組件已經(jīng)有了相當(dāng)深刻的認(rèn)識了,但是還沒完,我們必須做的一個步驟就是烘焙場景,生成導(dǎo)航網(wǎng)格。為什么要這樣做呢?因為Unity3d自帶的尋路系統(tǒng)的原理是事先通過烘焙將地形的信息記錄起來存儲在NavMesh文件上。我們烘焙一次看看,其實做法很簡單 ,我們打開Navigation窗口,做法:Window>Navigation。然后選中Plane,出現(xiàn)下面截圖:


我們可以看到Navigation Static復(fù)選框,勾選它。那它的作用是什么呢?原來,每一個GameObject都可以標(biāo)記成靜態(tài)的或非靜態(tài)的,就想這樣:



我們看到Plane的右側(cè)有一個Static屬性,展開他我們可以看到:



這里面每一種靜態(tài)選項背后都包含一種技術(shù),比如Lightmap Static,用于生成光照貼圖對場景進行優(yōu)化。還有Occluder Static與Occludee Static,是關(guān)于Unity3d中與遮擋剔除技術(shù)有關(guān)的。好了,言歸正傳,導(dǎo)航網(wǎng)格代理是在導(dǎo)航網(wǎng)格上周游的。所以我們的地面必須生成導(dǎo)航網(wǎng)格,這里的Navigation Static屬性框必須勾上。這時我們看到了第二個屬性框:OffMeshLink Generation,勾選上之后我們就可以不借助OffMeshLink組件來生成OffMeshLink。那么什么是OffMeshLink呢?請看下圖:



看到那些個線沒有?每一條線就代表一個OffMeshLink。那么此時我可以引入OffMeshLink組件了,這個組件其實就是自定義像上圖那樣的樣條線,但每一個OffMeshLink組件只能形成一個樣條線。這個樣條線的作用可不一般啊,但是應(yīng)用其時我們必須格外注意一些問題,不然我們即使用了這個組件也不會產(chǎn)生絲毫的作用的。
      那好吧,我們該做點什么了!
      如上圖,我建了連個Plane,分別為Plane1,Plane2。我們一次選擇這兩個平面,在Navigation窗口將Navigation Static 與Off Mesh Link Generation選項給勾上,并選擇Navigation Layer為Default。然后單擊Bake按鈕,如下:


我們還建立一個圍墻,用Cube做的,我們在Navigation面板中除了勾選Navigation Static之外,還必須將其Navigation Layer下拉框中選擇Not Walkable,即讓我們的Hero繞過此障礙物達到目的地。Not Walkable只是導(dǎo)航網(wǎng)格層中的一個內(nèi)建層,我們還可以建立我們自己的導(dǎo)航網(wǎng)格層。關(guān)于導(dǎo)航網(wǎng)格層,我會在我的下一篇文章中詳細為您講解。

我們之前說過,導(dǎo)航網(wǎng)格代理的活動空間只能是導(dǎo)航網(wǎng)格,即NavMesh。但現(xiàn)在看來這句話可能需要修改一下了。因為導(dǎo)航網(wǎng)格代理還可能活動在OffMeshLink上面,所以我們可以在兩個平面上面建立OffMeshLink來連通兩個平面。我們現(xiàn)在沒有用Off Mesh Link組件,這樣就可以生成很多的OffMeshLink。但是我們發(fā)現(xiàn)烘焙后的場景沒有出現(xiàn)Off Mesh Link。到底是什么原因呢?原來,我們還得設(shè)置一些參數(shù):


我們看到了一個選項 :Jump Distance。我們將這個值調(diào)到4,再次烘焙一次,則出現(xiàn)了以下場面:



然后我們新建一個Cube,命名為:DS。將其放置在上圖中的白色的Cube所在的位置上,然后我寫一個腳本:

using UnityEngine;
using System.Collections;

public class SetHeroDes : MonoBehaviour {
  public Transform ds;//目的Cube的Transform
  private Vector3 origin;//存儲導(dǎo)航網(wǎng)格代理的初始位置
  private NavMeshAgent nma;//存儲導(dǎo)航網(wǎng)格代理組件

    void Start () {
        nma =  gameObject.GetComponent<NavMeshAgent>();
  //取得導(dǎo)航網(wǎng)格代理組件
        origin = transform.position;
  //實例化origin
    }

  void OnGUI()
  {
      if(GUILayout.Button("Start***n"))
      {
        nma.SetDestination(tf.position);
      //設(shè)置導(dǎo)航網(wǎng)格代理的目的地
      }
      if (GUILayout.Button("Resume"))
      {
        transform.position = origin;
        //恢復(fù)導(dǎo)航網(wǎng)格代理的位置為初始位置
      }
  }
}

我們將這個腳本綁定到Hero上,然后將DS拖拽到指定位置:


然后我們運行一下:







我們可以清楚的發(fā)現(xiàn),我們的Hero越過了重重阻壑,終于到達了目的地??墒菃栴}此時又隨之而來了:如果我們將Hero中的導(dǎo)航網(wǎng)格代理組件中的Auto Traverse Off Ms選項給去掉,它還會越過重重溝壑到達我們的目的地嗎?實驗證明這樣做是無法成功的。官方文檔對這個勾選的解釋為:
Automate movement onto and off of OffMeshLinks。大致是這樣的:自動移動并且將OffMeshLinks關(guān)閉。你想,OffMeshLink都關(guān)閉了,Hero還怎么過來呢?
      接下來我再來介紹OffMeshLink組件的用法了,操作非常簡單:
1.新建連個空的GameObject或者你用模型也行,分別取名為StartPoint和EndPoint。為了便于識別,我用的是Sphere,給它上個綠色,并調(diào)節(jié)StartPoint的位置為Plane1上面,EndPoint的位置咋Plane2上面;


2.接著我們新建一個空的GameObject,取名為:SingleOffMeshLink,并讓StartPoint與EndPoint成為其子物體,為SingleOffMeshLink加入OffMeshLink組件,做法:選中SingleOffMeshLink,然后再Unity菜單欄中:Component->Navigation->Off Mesh Link。

我們將StartPont拖拽到Start上,EndPoint拖拽到End上。最后烘焙一下場景(此時Plane1與Plane2在Navigation中的OffMeshLink Generation勾選給去掉,目的是自定義我們的OffMeshLink):



看到?jīng)],只生成了一條樣條線。這就是我們自己做的OffMeshLink。

專業(yè)領(lǐng)域包括網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計、商城開發(fā)、微信營銷、系統(tǒng)平臺開發(fā), 與其他網(wǎng)站設(shè)計及系統(tǒng)開發(fā)公司不同,成都創(chuàng)新互聯(lián)的整合解決方案結(jié)合了幫做網(wǎng)絡(luò)品牌建設(shè)經(jīng)驗和互聯(lián)網(wǎng)整合營銷的理念,并將策略和執(zhí)行緊密結(jié)合,為客戶提供全網(wǎng)互聯(lián)網(wǎng)整合方案。

當(dāng)前文章:Unity里面的自動尋路(二)-創(chuàng)新互聯(lián)
鏈接地址:http://muchs.cn/article8/dpsiop.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機服務(wù)器托管、網(wǎng)站建設(shè)標(biāo)簽優(yōu)化、手機網(wǎng)站建設(shè)動態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護公司