此文將介紹4種實現動態障礙的方法,2種基於navmesh,2種基於astar算法。
1.基於navmesh。
1.制作場景障礙:
a.有幾個獨立的障礙物,就定義幾個user area,即,一個場景僅僅支持一個字節數目的獨立障礙物
b.建立碰撞盒建立障礙物:
碰撞盒是可行走區域。
c.設置碰撞盒gameobject的navigation面板的object頁簽的navigation area屬性:
每個獨立障礙物對應一個前面步驟a中定義的area,如果幾個障礙一起動態生成或消失,則可以使用同一個area
2.代碼控制這些動態障礙物的生成和消失:
障礙物消失是它的碰撞盒區域加入navmesh尋路mask中,即障礙物區域可行走,生成是不加入mask中,該區域不可行走
開啟或關閉第幾個door:
_door += 2;//因為前面有3個內置area:walkable,not walkable和jump,假如_door=1,即_door+=2后_door=3, 下面的1<<3后1在右起第4個字節,即對於第4個area:door1 if (_flag > 0)//flag>0表示開門,即障礙物消失,該碰撞盒區域可行走,需把該area位 置為1 { navmesh_mask_ |= (1 << _door); } else { navmesh_mask_ &= (~(1 << _door));//該area位 置為0 }
3.真正用到的地方(上面所有的工作服務的對象,其實也是此動態障礙解決方法的思考起點,我就是想知道CalculatePath的第3個參數的作用才找到此解決方法的):
所謂障礙物,影響的就是尋路!當障礙物消失時我們需要讓此區域可行走,沒消失時不可行走,下面是尋路代碼:
NavMeshPath nav_path = new NavMeshPath(); if (NavMesh.CalculatePath(src_pos, dis_pos, navmesh_mask_, nav_path))
即,通過控制calculatepath的第3個參數navmesh_mask實現動態障礙的控制:navmesh_mask每個位對應一個area,當某個area對應的位是0時尋路認為不可行走,1則可行走。
總結:此方法簡單明了,並且navmesh功能是官方提供的,性能方面占優。但這個動態障礙物必須是預先擺好的,不能像lol中亞索的盾牌那樣“隨意區域”動態,不過一般這種假動態就已經足夠項目使用了。
看來要繼續研讀navmesh文檔,看官方有沒有提供解決真動態障礙的方案了。
更新更新:打臉了,打臉了,用NavMesh Obstacle組件就能輕易讓一個gameobject變成障礙物並重新計算尋路網格,這個好啊,是真動態!明天測試一下。
再次更新再次更新:因為使用navmesh_mask的方式不需要重構尋路網格,所以性能很好,所以把navmesh_mask和navmesh obstacle結合起來使用:
固定位置的動態障礙物使用navmesh_mask,不固定位置的動態障礙物使用navmesh obstacle,這樣也不算打臉了=。=
2.基於astar,動態障礙物狀態更新時,都需要重新計算“可行走”網格,即把障礙物所在區域改成可行走,重新設置整個網格的“可行走”區域,讓尋路變得正確。這個astar插件已經基本做好了,讀者可以查閱其文檔即可。
大致說一下2種解決方法:
1.astar的動態障礙物實例腳本是這樣的:一個帶collider的gameobject,每次移動都調用一下:
AstarPath.active.UpdateGraphs(oldbounds);AstarPath.active.UpdateGraphs(newbounds);//oldbounds表示舊位置的bounds,new表示新位置的包圍盒立方體
其實就是刷新一下網格某個區域,對這個區域的每個網點檢測:如果被帶collider的物體占,則不可行走,否則可行走。這明顯可以解決隨意位置動態障礙問題,並且用法簡單,可以考慮。
2.還有另外一種方法,也是我目前項目使用的:不依賴collider,直接輸入一個bounds,然后把這個bounds和整個網格相交,得到需要更新的bounds區域,然后直接對整個區域的網點node進行設置是否可行走:
GridGraph mGridGraph=null; NavGraph[] graphs = AstarPath.active.graphs; for(...) { if (graphs[i] is GridGraph) { mGridGraph = graphs[i] as GridGraph; break; } } ...//計算需要設置的網點外殼 mGridGraph.nodes[z * mGridGraph.width+x].Walkable = pWalkAble;
本文總結:本文基於navmesh給出了2種解決方法,實際應用時可以結合起來提高性能,基於astar也提出了2種解決方法。