zoukankan      html  css  js  c++  java
  • 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种解决方法。

  • 相关阅读:
    快速提取某一文件夹下所有文件名称
    CFileFind类的使用总结
    FILE文件流的中fopen、fread、fseek、fclose的使用
    经典损失函数:交叉熵(附tensorflow)
    tensorboard使用
    Windows下 tensorboard出现ValueError:Invalid format string
    新建全色或者resize(毫无价值,只是做记录)
    创建一个任意大小的全色矩阵 python
    转移图片位置
    getpatch
  • 原文地址:https://www.cnblogs.com/Tearix/p/6919439.html
Copyright © 2011-2022 走看看