detour 寻路核心逻辑 CrowdToolState::updateTick dtCrowd::update

CrowdToolState::updateTick(constfloatdt)作为寻路模拟过程的主要函数主要就是干3件事:1 crowd->update(dt, &m_agentDebug);2 Update agent trails表示agent的足迹,不是寻路的必要部分,可以不用3 m_agentDebug.vod->normalizeSamples();...
摘要由CSDN通过智能技术生成

CrowdToolState::updateTick(constfloatdt)

作为寻路模拟过程的主要函数主要就是干3件事:

1 crowd->update(dt, &m_agentDebug);

2 Update agent trails表示agent的足迹,不是寻路的必要部分,可以不用

3 m_agentDebug.vod->normalizeSamples();

后面两步都是用来demo展示用的

 

主要逻辑:

dtCrowd::update(constfloatdt,dtCrowdAgentDebugInfo*debug)

 

m_state->hilightAgent(ahit);选择了一个agent的时候,便设置了m_agentDebug.idx

debugIdx中就记录了我们点亮的是哪个agent

agentactiveremove的时候设置为false

 

接下来就是寻路部分:

 

关于寻路过程我的理解:

首先当接到request的时候,先进行短寻路

寻路不到target就进行长寻路

长寻路有迭代次数的限制不至于让一个tick走的太多

必须长寻路因为全靠短寻路结果可能根本不是最好的,可否一定能寻到目的地?

然后每隔一段时间进行optimize

为了处理出现误差和由于动态阻挡而导致的当前路径已经不是最优的情况

几个例子:之前被动态阻挡导致需要转弯,但是动态阻挡已经不在那了,这个时候隔一段时间进行一次优化是有意义的

optimize结果可能有两种:一是跟之前的路径能连上,另一种是连不上,连不上的话直接返回,也就是说没有进行优化。

那么如果当前的路径遇到了阻挡呢?就是在checkPathValidity中检测出来申请重新寻路。

 

步骤:

1 checkPathValidity

    总得来说就是先确保startposstartRef的有效性

    以及在ag->corridor.fixPathStart确保path当中的第一个polygon是有效的

    其实就是让path[0]agentRef

    而留下其他的不管,让replanner去调整

    其他还有三种需要replan的情况

2 updateMoveRequest

    InitSlicedFindPath 做寻路的初始化工作

    updateSlicedFindPath 主要工作:

            相当于进行了一次类似A*的短寻路,并且记录结果

    这个过程首先当接收到request的时候进行短寻路,最后收集寻路结果的时候,如果是刚才的replan的情况,也就是当前路径是正在被重新规划,则执行

    finalizeSlicedFindPathPartial尽可能使用已有路径,否则说明目标被重置,需要执行finalizeSlicedFindPath

    finalizeSlicedFindPath翻转了updateSlicedFindPath的类似A*寻路的路径结果并保存。

 

    经过短寻路没走到头的ag->targetState= DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE

    并且将agent addToPathQueue,然后再dtPathQueue::update

    然后进行一次长寻路

    这次长寻路是从ag->corridor.getLastPoly()ag->targetRef

    然后将两次寻路的结果merge到一块

    放到res

    然后ag->corridor.setCorridor(targetPos, res,nres);

 

3 updateTopologyOptimization

      https://blog.csdn.net/icebergliu1234/article/details/88393735

 

4 对每一个agent的边界 进行更新,并且找到neibour放到neis里面

m_grid分配一块item记录agent

for (inti= 0; i < nagents;++i)

{

    ap.collisionQueryRange = ap.radius * 12.0f;

表示多长的距离的移动算是移动了

updateThr =ag->params.collisionQueryRange*0.25f;是否进行update更新碰撞边界的阈值

 

ag->npos, ag->boundary.getCenter()这两个的距离超过了updateThr

或者ag->boundary中的poly有无效的,说明需要update

 

接下来更新边界

dtLocalBoundary::update

在移动了一定的距离后,更新碰撞边界

或者碰撞边界已经变得invalid

并且ag->nneis= getNeighbours查询neighbour agents并且记录在ag->neis里面

}

 

5 接下来找到要前往的corners

for (inti= 0; i < nagents;++i)

{

    ag->corridor.findCorners

    corners的信息被存储在dtCrowdAgent里的三个数组里面

    float cornerVerts[DT_CROWDAGENT_MAX_CORNERS*3];

unsigned char cornerFlags[DT_CROWDAGENT_MAX_CORNERS];目前是三种,起始,终点,offmeshconnection

    dtPolyRef cornerPolys[DT_CROWDAGENT_MAX_CORNERS];里面是polyreference id

如果agent启用了DT_CROWD_OPTIMIZE_VIS也就是使用optimizePathVisibility来优化path

    做的事情就是shortcut到下一个可见的corner

}找到前往的corners完毕

 

 

6 接下来触发所有的off-meshconnections 这一段主要用来表现,所以可以由项目游戏模块自己来实现

for (inti= 0; i < nagents;++i)

{

    triggerRadius是触发半径

overOffmeshConnection(constdtCrowdAgent*ag,constfloatradius)判断是否经过了OffmeshConnection

    如果是corners里面有OffmeshConnection,肯定是最后一个

    因为在findcorners里面就是这么设定的

    所以判断ag->cornerFlags[ag->ncorners-1]& DT_STRAIGHTPATH_OFFMESH_CONNECTION

    如果当前位置ag->npos与这个cornner的距离小于触发半径则overOffmeshConnection返回true

 

    if(overOffmeshConnection(ag,triggerRadius))

{

    说明triggerRadius范围内有OffmeshConnection

ag->corridor.moveOverOffmeshConnection(ag->cornerPolys[ag->ncorners-1],refs,anim->startPos,anim->endPos,m_navquery))

这个函数找到了OffmeshConnection的两个端点,作为anim->startPosanim->endPos

    如果找到了

设置这个agentdtCrowdAgentAnimation* anim

    设置播放时间tmax为以两倍ag->params.maxSpeed速度走完跳点的时间

    并且ag->

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值