0x00 前言
unity5.6作為Unity5最后的一個版本,的確起到了一個承上啟下的作用。除了上一篇文章《進擊的AssetBundles和它的工具們》中提到的AssetBundles-Browser,本文還會介紹另一個在Github開源的,用於Unity5.6+的新尋路功能。
0x01 曾經的痛點
Unity5.6之前的navmesh系統的確操作起來十分容易上手,門檻很低。我們只需要將場景內需要烘焙navmesh的區域勾選上Navigation Static選項,之后就可以在Navigation窗口中烘焙整個場景了。
但是曾經的navmesh系統卻也存在着一些性能上的和使用場景上的缺陷。
一個常見的問題,由於要預先烘焙場景的navmesh,因此我們很難方便的在運行時動態的修改navmesh。更不用說,有一些游戲的場景並非提前制作好的,需要在運行時動態的生成,這種情況下就無法使用navmesh了。
另一個問題是,如果場景過大的話,烘焙之后的navmesh也會保存很多數據,在運行時會造成一些內存上的開銷。
當然,拋開這些不談,另外一個讓我吐槽navmesh的一點就是,它竟然不支持垂直面的導航。
在做一些2d的platform游戲時,我很希望能利用navmesh來實現尋路的邏輯。(圖文無關)
但是,不幸的是,之前的navmesh是不支持的。
0x02 組件化的navmesh
不過還好,雖然新的navmesh系統並沒有隨着unity的正式版本一同發布。但是,我們還是可以通過github來獲取這些新的功能:
需要注意的是,Unity的版本要求在5.6以上。
我們可以看到,其實這里只有4個高層的C#腳本文件:
利用這4個腳本文件,就能基本解決我們之前的煩惱了。
其中NavMeshSurface這個腳本將navmesh組件化,利用這個組件就可以很方便的烘焙掛載該組件的對象的navmesh信息,而無需打開一個navigation窗口對整個場景進行烘焙了。我們甚至可以將掛載這個腳本的GameObject烘焙后保存為一個prefab,這個帶有navmesh信息的prefab跟其他的prefab一樣。
為對象添加NavMeshSurface組件很簡單。在這里我們可以看到和之前navigation窗口類似一些設置,但是請注意,這里已經不是整個場景烘焙了。navmesh已經組件化了,它只會烘焙掛載它的對象。
只要點擊一下這個組件下的Bake按鈕,掛載它的對象就被烘焙好了。
那么GameObject能否掛載多個NavMeshSurface組件呢?這一種需求也的確存在,例如怪物和玩家的尋路策略不同,有些地方玩家能通過而怪物卻不能通過。
這的確也是可以的,同一個GameObject能夠同時掛載多個NavMeshSurface組件,並且烘焙不同的navmesh供不同的角色使用。
這樣,我們針對不同的角色的NavMeshAgent組件設置不同的agent type並和烘焙好的兩個navmesh匹配好就可以了。
0x03 飛檐走壁
好了,借助NavMeshSurface組件我們實現了navmesh的組件化。那么是不是我們就能很方便的實現在垂直面上烘焙navmesh了呢?各位想想我們是否能很輕松的讓一個游戲對象的角度改變呢?答案是是的。那么這個游戲對象上如果有navmesh信息的話,我們只需要把這個游戲對象從水平變為垂直是否就行了呢?是的。
因此實現游戲角色的在垂直面上飛檐走壁的功能就變得十分簡單了。
當然了,在水平面的navmesh和垂直面的navmesh之間我們還會用到NavMeshLink這個組件來鏈接二者。各位自己在實踐的時候需要留意一下這一點。
0x04 在運行時烘焙navmesh
接下來就讓我們看看新的navmesh系統帶給我們的新的驚喜——在運行時烘焙navmesh。
這是一個很現實的需求,例如一些動態生成場景的游戲,我們無法在一開始就確定這個場景到底是什么樣子的,所以也無法使用之前的navmesh系統,因為以前的navmesh只能在editor內烘焙。但是現在我們使用新的navmesh系統就能夠很方便的在運行時烘焙navmesh了。
如圖,這是一個空場景,在游戲運行之后場景才生成出來場景內的各種道路,此時單擊鼠標,navmesh就生成了。
其實在新的navmesh系統內,實現這個機制十分簡單。只需要調用游戲對象上掛的NavMeshSurface組件的BuildNavMesh()方法。
void Start()
{
surface = GetComponent<NavMeshSurface>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
surface.BuildNavMesh ();
}
}
既然navmesh已經可以在運行時創建了,那么我們能否也在運行時實例化一個navmesh的prefab,實時的影響場景內的尋路策略呢?
答案是當然可以。
0x05 場景太大不用愁
自己做過尋路算法的童靴可能會意識到一個問題,就是在做尋路時如果場景過大的話,尋路的數據可能會比較消耗內存。同樣在navmesh中,如果場景過大,或者玩家的視野范圍有限,一些對玩家當前位置影響不大的場景的其他位置的navmesh數據就有可能造成一些無謂的消耗。
在新的navmesh系統中,我們同樣可以優化這個問題,只烘焙玩家周圍的navmesh。
這里同樣需要NavMeshSurface組件,在inspector視窗我們可以選擇collect object中的volume,之后設定size的值就可以值烘焙這個范圍內的navmesh了。之后隨着玩家的移動,再動態烘焙新的navmesh就可以了。
ref:
【1】High-level NavMesh Building Components
【2】Unite Europe 2017 - Finding the path: New navigation features
各位如果覺得有趣的話,歡迎點個贊。
-EOF-
最后打個廣告,歡迎支持我的書《Unity 3D腳本編程》
歡迎大家關注我的公眾號慕容的游戲編程:chenjd01