Crowd Actor

ACrowdToolkitActor (display name Crowd Toolkit Actor) is the one object you interact with. It wraps the simulation library as an Actor: every tunable lives as a property in its details panel, and every operation - spawn, order, query, walls - is a Blueprint-callable function.

Each actor owns its own independent simulation (created on BeginPlay, destroyed on EndPlay), so any number of crowd actors can run side by side. All positions are in world space; the simulation's X/Y maps directly to world X/Y, and Z is tracked per agent.


Configuration properties

All config properties are EditAnywhere + BlueprintReadWrite. They are copied into the simulation every tick (via ApplyConfig), so changing one at runtime takes effect immediately. Clamp ranges below are the valid limits; the simulation re-clamps on apply.

Crowd actor details panel
Crowd actor details panel

Agent

Property Default Range Description
Radius 15 1 – 60 Agent collision radius. Global - every agent shares it.
Speed 100 ≥ 0 Default max speed for agents with no per-agent override. Uncapped on top.
Acceleration 400 0 – 5000 How fast agents speed up, units/s². 0 = instant.
Deceleration 600 0 – 5000 How fast agents slow down, units/s²; also shapes the arrival braking curve so stops ease out. 0 = instant.
Turn Rate 540 0 – 1440 Max heading change while travelling, deg/s - agents arc into new directions instead of flipping. 0 = unlimited.
Stuck Timeout 2 0 – 30 Seconds without progress before OnAgentsStuck reports an ordered agent (re-fires each interval). 0 disables stuck events.

Formation

See Formations.

Property Default Range Description
Shape Blob enum Blob, Box, or Wedge.
Settle Radius 10 1 – 50 How close to its slot an agent must be to count as settled.
Slot Spacing 1.1 0.5 – 2 Slot spacing, in agent diameters.

See Navigation.

Property Default Range Description
Mode Flow Field enum None, Flow Field, or Spatial A*.
Tile Size 20 4 – 64 World units per routing cell.
Smooth Flow true bool Flow Field only. Gradient flow vs nearest-of-8 directions.

Avoidance

See Avoidance. Always on - these only tune it.

Property Default Range Description
Strength 150 0 – 1000 Mutual push between two travelling agents.
Settle Push 50 0 – 1000 How strongly a settled agent steps aside for a passer-by.

Walls

See Wall Generation.

Property Default Range Description
Has Collision true bool Gates physical wall collision. Off = walls still block pathfinding but agents can pass through.
Tile Size 40 4 – 64 World units per wall tile.
Near Wall Cost 3 1 – 20 Pathfinding traversal multiplier for open cells next to walls. 1 disables the bias.
Wall Generation Method Nav Mesh enum Wall source baked once on BeginPlay: None or Nav Mesh.
Generate Nav Mesh Border Walls false bool Also wall off the nav mesh's outer border, sealing agents inside it.

Ground

See Ground Snapping.

Property Default Description
Snap To Ground false Re-trace the ground under each agent every tick and glue its Z to the hit. Off = agents keep their spawn Z.
Ground Trace Channel Visibility Collision channel the ground trace runs against.
Ground Trace Up Limit 200 Trace starts this far above the agent's current Z.
Ground Trace Down Limit 200 Trace ends this far below the agent's current Z. On a miss the agent keeps its Z.
Ground Offset 0 Added to the hit to get the agent's Z (e.g. mesh half-height).
Ground Trace Ignored Actors [] Actors the trace ignores. Add your crowd renderer here (see the self-collision trap).
Max Ground Traces Per Tick 0 Cap on ground re-traces per tick (round-robin). 0 = trace every agent every tick.
Align Transforms To Ground false Tilt rendered transforms to the traced ground normal (slopes). Needs Snap To Ground.

General

Property Default Description
Auto Tick true Advance the simulation automatically each frame in Tick. Turn off to drive it yourself with SimTick.
Reset On Begin Play true Clear the simulation to empty when play begins.
Transform Scale 1 Uniform scale applied to transforms from GetAgentTransforms.

Debug

There is no master switch: each overlay is drawn every tick when its own flag is on, so untick them all to draw nothing. All default to off and are compiled out of Shipping builds. See Debugging.

Property Default Description
Draw Walls false The wall grid, one gray box per tile.
Draw Agents false Every agent as a sphere of the agent radius (green when settled, white while moving).
Show Slots false The slot rings agents settle onto.
Show Nav Goals false Each agent's shared formation anchor.
Show Velocity false Each agent's velocity vector.
Show Flow Field false Per-cell flow arrows of every active flow field. Only populated in Flow Field navigation mode.
Show A* Paths false Each agent's current cached route as a polyline. Only populated in Spatial A* navigation mode.

Functions

Simulation control

void SimTick(float DeltaSeconds);

Advance the simulation by DeltaSeconds (pushes the current config first). Called automatically each frame when Auto Tick is on; call it yourself when you've turned Auto Tick off and want to drive the step manually. DeltaSeconds is clamped and substepped internally, so a frame hitch slows simulated time briefly instead of letting agents tunnel through walls.

void ResetSimulation();

Clear all agents, walls and pathfinding/avoidance caches (config is kept). Pending spawned/removed event batches are discarded - the indices they named no longer exist.

void ApplyConfig() const;

Copy the actor's config properties into the simulation. Done automatically each tick; rarely called directly.

Spawning & removing

void SpawnAgent(const FVector& Position);

Spawn one agent at Position. Position.Z becomes its initial tracked Z; the simulation itself takes only X/Y. Reported via OnAgentsSpawned.

void SpawnAgentGrid(const FVector& Origin, int32 Cols, int32 Rows, float Spacing);

Spawn a Cols × Rows grid of agents starting at Origin, Spacing apart.

void RemoveAgent(int32 Index);

Queue the agent at Index for removal. Removals are deferred: the simulation applies the queued batch (sorted, swap-and-pop) at the start of the next tick, so indices stay stable between ticks and any set of agents can be removed in any order. Until that tick the agent is still present (count and getters include it). Out-of-range indices and re-queues of an already-queued index are ignored. Reported via OnAgentsRemoved before the removing tick, while the index is still valid.

int32 GetAgentCount() const;

Number of agents currently in the simulation (includes agents queued for removal until the next tick applies the removal).

Identity - indices & ids

See Indices & Stable IDs. Lookups that miss return -1.

int32 GetAgentId(int32 Index) const;   // stable id at Index, -1 if out of range
int32 GetAgentIndex(int32 Id) const;   // current index of Id, -1 if no such agent
TArray<int32> GetAgentsIds(const TArray<int32>& Indices) const;   // id per index, -1 per out-of-range
TArray<int32> GetAgentsIndices(const TArray<int32>& Ids) const;   // index per id, -1 per unknown

Batch forms - translate a whole selection in one call. Output is parallel to the input.

Per-agent getters

Each getter takes an optional Indices mask: pass an empty array to get every agent in storage order; pass a list of indices to get exactly those, in mask order (an out-of-range index yields a zeroed entry, so the output always lines up 1:1 with the mask). All the getters below are parallel - element i of each refers to the same agent.

TArray<FVector> GetAgentPositions(const TArray<int32>& Indices) const;

World positions, including each agent's tracked Z.

TArray<FTransform> GetAgentTransforms(const TArray<int32>& Indices) const;

Render-ready transforms: location = agent position; rotation faces the travel direction (holding the last facing while standing still), tilted to the ground normal when Align Transforms To Ground; scale = Transform Scale on every axis. See Rendering Agents.

TArray<FVector> GetAgentGroundNormals(const TArray<int32>& Indices) const;

Last traced ground normal per agent (world up until a trace has hit). See Ground Snapping.

TArray<FVector> GetAgentTargets(const TArray<int32>& Indices) const;

Each agent's individual formation slot position.

TArray<FVector> GetAgentNavGoals(const TArray<int32>& Indices) const;

The shared formation anchor the group is routing toward.

TArray<FVector> GetAgentVelocities(const TArray<int32>& Indices) const;

Current velocities - use the magnitude to drive idle/walk/run animation.

TArray<bool> GetAgentSettled(const TArray<int32>& Indices) const;

Latched settle (arrived) state per agent.

TArray<float> GetAgentSpeeds(const TArray<int32>& Indices) const;

Effective max speed per agent - the per-agent override where set, otherwise the Speed config value.

Selection queries

Return indices into the position array. The screen-rect query is the marquee-select replacement; doing it per agent in a Blueprint loop costs a visible hitch at high counts.

TArray<int32> GetAgentsInRect(const FBox2D& Rect) const;

Every agent inside the world-space XY rectangle.

TArray<int32> GetAgentsInRadius(const FVector& Center, float Radius) const;

Every agent within Radius of Center on the XY plane (Center.Z ignored).

TArray<int32> GetAgentsInScreenRect(APlayerController* PlayerController,
                                    const FVector2D& ScreenMin,
                                    const FVector2D& ScreenMax) const;

Every agent whose position projects inside the screen-space rect [ScreenMin, ScreenMax] (inclusive) for the given player - marquee selection in one call. Projection uses each agent's tracked Z, so it matches what the player sees.

Orders

void SetAgentsTarget(const TArray<int32>& Indices, const FVector& Position);

Order Indices into a formation centred on Position. The core movement call. Replacing an unfinished order fires OnAgentsOrdersCanceled for the affected agents.

void SetAgentTarget(int32 Index, const FVector& Position);

Single-agent convenience - a formation of one, so the agent simply walks to the point.

Per-agent speed

On top of the global Speed default, you can cap individual agents.

void SetAgentsSpeed(const TArray<int32>& Indices, float Speed);
void SetAgentSpeed(int32 Index, float Speed);

Set the max-speed override. Speed < 0 resets the agents to the global Speed config value; Speed >= 0 is an absolute per-agent cap (0 freezes them in place). Read the effective values back with GetAgentSpeeds.

Walls

See Wall Generation.

void AddWallTile(int32 X, int32 Y);

Block the wall-grid tile at (X, Y). Idempotent - adding an existing tile is a no-op.

TArray<FIntPoint> GetWallTiles() const;

Every blocked wall tile, as grid coordinates.

int32 GenerateWallTiles();

Generate walls using the selected Wall Generation Method (None is a no-op). Called once on BeginPlay; returns the number of tiles added.

int32 GenerateWallTilesFromNavMesh();

Rasterize the world's built navigation mesh into the wall grid (see Seeding walls from the nav mesh). Requires the nav mesh to be built; safe to call repeatedly. Returns the number of tiles added.


Events

Multicast delegates - bind in Blueprint or C++. Full timing and usage in Events.

Event Delivers When
OnAgentsSpawned indices before the tick that adds them
OnAgentsRemoved indices before the tick that removes them (indices still valid)
OnAgentsReachedGoal indices after a tick, once per arrival
OnAgentsStuck indices after a tick, repeating while stuck
OnAgentsOrdersCanceled indices after a tick, when an order is replaced

Debugging & diagnostics

Tick any of the debug flags (Draw Walls, Draw Agents, Show Slots, Show Nav Goals, Show Velocity, Show Flow Field, Show A* Paths) to draw that overlay into the world. There is no master switch; untick them all to draw nothing.

int32 GetFlowFieldCount() const;   // number of cached flow fields
int64 GetFlowFieldBytes() const;   // their total memory

The cache grows with the world region the agents span - handy for understanding memory under Flow Field navigation.