Recast/Detour  2.0.2
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Crowd Management


This module is about handling multiple agents.

dtCrowd is the class representing a crowd.

A crowd handles every agent it contains. You can think of it as a big container for agents.

You can see dtCrowd as an interface between you and the agents it contains. You cannot modify the agents inside the crowd directly, the interface will only grant you a constant access to the data.

Through dtCrowd you can do several things:

How to create a crowd

Here is a sample code for creating a crowd:

// Creation of the crowd.
dtCrowd crowd;
// How many agents can the crowd contain?
int nbMaxAgents = 1000;
// The maximum radius for an agent
float maxRadius = 10.f;
// How close should an element be before being considered as an obstacle?
float collisionRange = 4.f;
// Note: the navigation mesh must already be initialized
// The navigation mesh will be used by the agents for navigation
crowd.init(nbMaxAgents, mawRadius, navigationMesh, collisionRange);

You now have a crowd ready to work, but empty...


dtCrowdAgent is the class representing an agent.

An agent is an entity inside a crowd with several properties. The most important of these is the dtCrowdAgent::id property.

Each agent is identified by its id, and the crowd handles its agents using these ids. Therefore the user should not modify the id of an agent by himself. The ids are generated by crowd and are unique.

Add an agent to the crowd

When you create a crowd, you create the agents at the same time. Indeed the crowd will create N agents, N being the maximum of agents you specified when creating the crowd, and set them as inactive. If inactive, an agent won't be taken into account during the process of updating the crowd.

Here is how you can toggle an agent as active/inactive:

// The position you want to place your agent at
float position[] = {0, 0, 0};
if (crowd.addAgent(agent, position) == false)
// Error The agent could not be added to the crowd
// At this point, agent has been added and set as active. Its data (and id) have been updated.
// You can also remove the agent from the crowd, which will set him as inactive

With the method dtCrowd::addAgent() we can toggle an agent as active an place it at a specific point on the navigation mesh. The method will copy the data of the newly created agent into the agent structure you provided. You can use the id of the agent later on to get access to it thanks to the method dtCrowd::getAgent().

Your crowd now contains one agent.

Access and edit existing agents

dtCrowd does not allow you to directly edit the agents. You need to get a copy of the agent, edit it, then send the modifications to the crowd. In any case, you will need the id of an agent in order to retrieve it.

Here is a code illustrating the different ways to access agents:

// You can get a const access to an agent with its id
const dtCrowdAgent* ag = crowd.getAgent(id);
// You can fetch an agent and copy the data into another agent
dtCrowdAgent myAgent;
crowd.fetchAgent(myAgent, id);
// You can also get several agents at the same time
int ids[] = {1, 2, 3, 6};
const dtCrowdAgent* agents[4];
int nbAgentsFound = crowd.getAgents(ids, 4, agents);

Now that you have accessed your agent, you might want to modify some of its properties, and then send the changes to the crowd, here is how this can be acheived:

// Fetch the agent you want to edit
crowd.fetchAgent(ag, id); // The data have been copied into ag (including the id)
// Edit the properties
ag.maxSpeed *= 2;
ag.radius = 10;
ag.height = 500;
// ...
// You can now send the changes to the crowd
dtCrowd uses the id when looking for and editing an agent, therefore be careful not the change the id property of an agent, otherwise the crowd might not update the right agent.

Update the crowd

When you update the crowd, by default, all the active agents inside this crowd will be updated. But maybe you just want some of them to be updated. This can be done by providing a list of agents' ids.

When updating the agents, the crowd will use the behaviors assigned to them. See the Behaviors module for more details.
float position1[] = {0, 0, 0};
float position2[] = {1, 0, 1};
float position3[] = {2, 0, 2};
dtCrowdAgent ag1, ag2, ag3;
if (!crowd.addAgent(ag1, position1) || !crowd.addAgent(ag2, position2) || !crowd.addAgent(ag3, position3))
return false;
// ...
// Updates every active agents inside the crowd.
crowd.update(dt); // dt is the delta time to update the simulation.
int list[2];
list[0] =;
list[1] =;
// Just the agents 2 and 3 will be updated.
crowd.update(dt, list, 2);
// Just the agent corresponding to index2 will be updated (since we say the list has a size of 1).
crowd.update(dt, list, 1);

Crowds updating is a three parts process, for each agent we do the following:

The calls order should be this:

You can individually call these updates using the following methods:

Calling the method dtCrowd::update() will call all three methods listed above.

Other features

Change the position of an agent

Of course the position of an agent will be updated trough its behavior(s), but sometimes you might want to set your agent at a given position instantly, without the constraints of a behavior (for instance your agent have walked on a teleporter). This can be done using the dtCrowd::pushAgentPosition() method:

float newPosition[] = {10, 0, 0};
if (crowd.pushAgentPosition(agentId, newPosition))
// Done, your agent has moved
// Something went wrong, either the position is invalid or the given id was out of bounds

Access the environment of an agent

The environment of an agent contains many informations that can be useful for some behavior (for instance it is used by the behavior dtCollisionAvoidance).

You can retreive the environment of an agent by using the method dtCrowd::getAgentEnvironment.

The Crowd Query

dtCrowdQuery contains informations that dtCrowd uses and that might be useful for the user. It contains things like the proximity grid, the animations of the agents, the dtNavMeshQuery, etc.

Since it might often be useful, dtCrowd provides an easy access via the method dtCrowd::getCrowdQuery().


struct  dtCrowdNeighbour
 Provides neighbor data for agents managed by the crowd. More...
struct  dtCrowdAgentEnvironment
 The environment of an agent. More...
struct  dtCrowdAgent
 Represents an agent managed by a dtCrowd object. More...
class  dtCrowdQuery
 Utility class used to get access to some useful elements of the crowd. More...
class  dtCrowd
 Class containing and handling the agents of the simulation. More...


 The type of navigation mesh polygon the agent is currently traversing. More...


dtCrowddtAllocCrowd ()
 Allocates a crowd object using the Detour allocator. More...
void dtFreeCrowd (dtCrowd *ptr)
 Frees the specified crowd object using the Detour allocator. More...


 The maximum number of neighbors that a crowd agent can take into account for steering decisions. More...

Enumeration Type Documentation

The type of navigation mesh polygon the agent is currently traversing.


The agent is not in a valid state.


The agent is traversing a normal navigation mesh polygon.


The agent is traversing an off-mesh connection.

Function Documentation

dtCrowd* dtAllocCrowd ( )

Allocates a crowd object using the Detour allocator.

A crowd object that is ready for initialization, or null on failure.
void dtFreeCrowd ( dtCrowd ptr)

Frees the specified crowd object using the Detour allocator.

[in]ptrA crowd object allocated using dtAllocCrowd

Variable Documentation


The maximum number of neighbors that a crowd agent can take into account for steering decisions.