This question is specifically about dealing with the Recast Navigation library.

I have added an agent with addAgent and set its target with requestMoveTarget. When agent reaches its destination, it stops, but when being pushed out of the way (by another agent) it will try to return back to its target. Instead, want it to stop and become idle, so that when other agent walking by push it aside and it wont return back.

I have tried calling resetMoveTarget upon agent.npos being close to agent.targetPos (as if agent has reached its destination), but that seems to break the inner logic of the crowd simulation - the agent would just keep walking in old direction, never stopping.

How do I properly tell an agent to stop and become idle (yet pushable) in RecastNavigation?


A fix was made upstream related to your solution that resets the desired velocity in resetMoveTarget.

bool dtCrowd::resetMoveTarget(const int idx)
    if (idx < 0 || idx >= m_maxAgents)
        return false;

    dtCrowdAgent* ag = &m_agents[idx];

    // Initialize request.
    ag->targetRef = 0;
    dtVset(ag->targetPos, 0,0,0);
    dtVset(ag->dvel, 0,0,0); // <<-- This line added
    ag->targetPathqRef = DT_PATHQ_INVALID;
    ag->targetReplan = false;
    ag->targetState = DT_CROWDAGENT_TARGET_NONE;

    return true;
  • \$\begingroup\$ As far as I can recall this is incomplete answer. I'm confused. Is this an answer or a comment to my answer below? Because you also need to reset agents corridor, so that the agents becomes truly idle (pushable). \$\endgroup\$ – Kromster May 2 '15 at 21:16
  • \$\begingroup\$ OK i had forgot about your issue with agent becoming unpushable. I'll try to reproduce. \$\endgroup\$ – Leif Gruenwoldt May 2 '15 at 21:36
  • \$\begingroup\$ @KromStern Hmm I'm having trouble reproducing this. Without the cooridor reset my agents are pushable by other agents. Is it necessary? \$\endgroup\$ – Leif Gruenwoldt May 4 '15 at 19:04
  • \$\begingroup\$ I tried adding this to resetMoveTarget locally but I don't observe a difference. ag->corridor.reset(ag->corridor.getFirstPoly(), agent->npos); \$\endgroup\$ – Leif Gruenwoldt May 4 '15 at 19:06
  • 1
    \$\begingroup\$ For some weird reason I can not reproduce it now either. Looks like something else has changed since then. Anyway, thanks for your participation! :) \$\endgroup\$ – Kromster May 7 '15 at 7:27

I am not sure but my guess would be to call "requestMoveVelocity" with zero-vector as well on that agent. Give it a try.


Note: This solution appears to be superfluous, but I'm leaving it in case the issue re-appears.

After a lot of decoding, trial and error I took dtCrowd.resetMoveTarget as a base and found a way to modify it:

procedure TKMTerrainNavigation.AgentTargetClear(aIdx: Integer);
  ag: PdtCrowdAgent;
  ag := fRecastCrowd.getAgent(aIdx);

  ag.targetRef := 0;
  dtVset(@ag.targetPos[0], 0, 0, 0);
  ag.targetPathqRef := DT_PATHQ_INVALID;
  ag.targetReplan := False;
  ag.targetState := DT_CROWDAGENT_TARGET_NONE;

  // Reset desired velocity
  dtVset(@ag.dvel[0], 0, 0, 0); 

  // Reset agents corridor so that agent won't try to walk back to his last corner
  ag.ncorners := 0;

P.S. Above code is in Delphi, but it should work just as well in C++.

Recast Navigation author commented:

Instead of resetting the corners, you should reset the corridor to agents current position and first polygon.

Setting target position to agents current position is generally preferred, than setting it to 0,0,0. But you're resetting everything else too, I think it is fine.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.