unity 4種實現動態障礙方法


此文將介紹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種解決方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM