Crowd avoidance location for agent using ICrowdAgentInterface not properly updated when going off the navmesh.

Hey,

Ive encountered an issue with the detour crowd. In our game we have some AI agents that uses the detour crowd avoidance and we have implemented the `ICrowdAgentInterface` on our player character so that the agents don’t just run into the player.

However one of our developers noticed that occasionally our AI still Ignores the player and just walks into him.

I checked with the detour crowd avoidance debug drawing `ai.crowd.DebugSelectedActors` and it seemed like the player was not detected as a neighbor of the AI agent anymore.

(See the screenshot. The white sphere is the player character and the selected actor is the AI agent)

Then after double checking that the `groupsToAvoid` and `groupsToIgnore` are setup correctly I believe I traced the issue down to the function `dtCrowd::updateStepCorridor` in `DetourCrowd.cpp`.

        dtCrowdAgent* ag = m_activeAgents[i];
        if (ag->state != DT_CROWDAGENT_STATE_WALKING)
            continue;

        // Move along navmesh.
        m_navquery->updateLinkFilter(ag->params.linkFilter.Get());
        const bool bMoved = ag->corridor.movePosition(ag->npos, m_navquery, &m_filters[ag->params.filter]);
        if (bMoved)
        {
            // Get valid constrained position back.
            dtVcopy(ag->npos, ag->corridor.getPos());
        }

        // If not using path, truncate the corridor to just one poly.
        if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
        {
            ag->corridor.reset(ag->corridor.getFirstPoly(), ag->npos);
        }

In here the agent location of the player is constrained to its corridor which in this case is just the navmesh polygon on which he is located If I understand correctly. But if the player moves off the navmesh his crowd agent location is still clamped to the navmesh which causes other agents to incorrectly avoid him.

When the player then again enters onto the navmesh his location is sometimes not updated as well which causes the issue we had where AI agents don’t avoid the player at all because the player agents location is outside the range where they would detect him as a neighbor.

From my testing moving the part of the function where the corridor is truncated before the part where we handle moving along navmesh seems to fix this issue.

        dtCrowdAgent* ag = m_activeAgents[i];
        if (ag->state != DT_CROWDAGENT_STATE_WALKING)
            continue;
        
        // If not using path, truncate the corridor to just one poly.
        if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
        {
            ag->corridor.reset(ag->corridor.getFirstPoly(), ag->npos);
            continue;
        }

        // Move along navmesh.
        m_navquery->updateLinkFilter(ag->params.linkFilter.Get());
        const bool bMoved = ag->corridor.movePosition(ag->npos, m_navquery, &m_filters[ag->params.filter]);
        if (bMoved)
        {
            // Get valid constrained position back.
            dtVcopy(ag->npos, ag->corridor.getPos());
        }

My questions are the following then:

  • Is it intended that agents that are not necessarily on the navmesh are constrained to the navmesh for detour crowd avoidance?
  • Could this be fixed? (our company has a strict no engine modification policy)

Kind Regards, Daan.

[Attachment Removed]

So this is a bit of an odd situation. This isn’t intended behavior, but the original intent was that DetourCrowd controls agents so they would be unable to leave the navmesh. In the case of the player, well, they always do find a way to get to areas not intended to be traversed.

There is good news! There is a way to work around this. Perhaps the best way would be to unregister the player with DetourCrowd when the player leaves the navmesh and register when returning to the navmesh. There could be issues when very near navmesh edge that cause a bounce between states, but that could likely be solved with using a small distance value for the difference in actual position and nearest point in the poly. I believe this would also solve the issue of the corridor for the avoiding agent as register/unregister should result in a new corridor being built.

-James

[Attachment Removed]