SwarmManager¶
namespace MassiveSwarmSystem.Runtime
The central component that owns the whole simulation: the agent data, the spatial grid, the
fixed-step simulation loop, target tracking, grounding, and blocking. You place one
SwarmManager in the scene (alongside a SwarmVisualManager) and everything else talks to it.
Setting it up in the Inspector
This page is the scripting view. For placing the manager, assigning a SwarmSettings
asset, and tuning the simulation in the Inspector, see
Swarm Manager.
Getting the manager¶
SwarmManager.Instance is the active manager (set on Awake). When you can't be sure one
exists yet, use TryGetManager, which falls back to a scene search and tells you whether it
found exactly one:
using MassiveSwarmSystem.Runtime;
if (SwarmManager.TryGetManager(out SwarmManager manager))
{
int alive = manager.ActiveAgentCount;
}
| Member | Description |
|---|---|
Instance |
The active manager, or null. Set automatically on Awake. |
TryGetManager(out SwarmManager manager) |
true if a single active manager was found. Silent. |
TryGetManager(out SwarmManager manager, bool logError) |
Same, but logs an error when zero or multiple managers exist. |
ActiveAgentCount |
How many agents are currently alive. |
Capacity |
Maximum agents (from SwarmSettings). |
Agent indices are not stable
Every per-agent method below takes an int agentIndex. Despawning uses swap-back: when an
agent is removed, the last agent is moved into the freed slot, so its index changes.
Treat an index as valid only until the next DespawnAgent call or simulation step. Get a
fresh index from TrySpawnAgent or your own per-frame lookup — never cache one across
frames and assume it still points at the same agent.
Spawning agents¶
TrySpawnAgent adds one agent and returns false if the swarm is at capacity (or not set up).
The position is automatically grounded using the manager's grounding settings. The simulation
self-initializes on the first spawn, so you don't have to call Initialize() yourself.
// Spawn a ring of agents using a configured archetype.
for (int i = 0; i < 200; i++)
{
float a = i / 200f * Mathf.PI * 2f;
Vector3 pos = center + new Vector3(Mathf.Cos(a), 0f, Mathf.Sin(a)) * radius;
if (!manager.TrySpawnAgent(pos, Vector3.forward, archetype, out int agentIndex))
{
break; // at capacity
}
}
| Overload | Use it when |
|---|---|
TrySpawnAgent(pos, forward) |
Quick spawn with the default radius and profiles. |
TrySpawnAgent(pos, forward, out int agentIndex) |
Same, but you need the new agent's index. |
TrySpawnAgent(pos, forward, SwarmBehaviorProfile) |
Override the behavior profile. |
TrySpawnAgent(pos, forward, SwarmBehaviorProfile, SwarmMovementProfile) |
Override both profiles. |
TrySpawnAgent(pos, forward, SwarmBehaviorProfile, SwarmMovementProfile, out int agentIndex) |
…and capture the index. |
TrySpawnAgent(pos, forward, SwarmAgentArchetype, out int agentIndex) |
Spawn from an archetype (prefab + radius + profiles + attack profile). Skips and warns if the archetype has no prefab. |
TrySpawnAgent(in SwarmAgentSpawnState, pos, forward, out int agentIndex) |
Re-spawn from a state captured with TryGetSpawnState (see below). |
Despawning agents¶
manager.DespawnAgent(agentIndex); // remove immediately
manager.DespawnAgentAsDying(agentIndex, 1.5f); // play a 1.5s dissolve, then pool the visual
| Member | Description |
|---|---|
DespawnAgent(int agentIndex) |
Frees the agent's slot immediately. Returns false for an invalid index. |
DespawnAgentAsDying(int agentIndex, float dissolveDuration) |
Frees the slot now but keeps the visual on screen, writing a dissolve amount for dissolveDuration seconds before pooling it. Falls back to an immediate release when the visual can't dissolve (instanced batch, no VAT, no pool). |
Despawning reindexes another agent
Both calls swap the last agent into the freed slot — see Agent indices are not stable above. If you're despawning several agents in a loop by index, despawn from the highest index down, or re-query indices between calls.
Moving agents and applying forces¶
Use these to teleport agents or push them around (knockback, explosions, wind):
// Knockback away from a blast.
Vector3 dir = (agentPosition - blastCenter).normalized;
manager.AddAgentImpulse(agentIndex, dir * 12f, externalControlDuration: 0.3f);
// Teleport an agent and reset its motion.
manager.RelocateAgent(agentIndex, spawnPoint.position, spawnPoint.forward);
| Member | Description |
|---|---|
RelocateAgent(int agentIndex, Vector3 position, Vector3 forward) |
Teleports the agent (grounded), clears velocity, steering, and external forces, and wakes it if dormant. A zero forward keeps the current facing. |
AddAgentImpulse(int agentIndex, Vector3 impulseVelocity) |
Applies an instantaneous velocity change (ForceMode.Impulse) using the default external-control duration. |
AddAgentImpulse(int agentIndex, Vector3 impulseVelocity, float externalControlDuration) |
Same, with an explicit duration the external velocity overrides steering. |
AddAgentForce(int agentIndex, Vector3 force) |
Applies a continuous force (ForceMode.Force). |
AddAgentForce(int agentIndex, Vector3 force, ForceMode forceMode) |
Choose the force mode. |
AddAgentForce(int agentIndex, Vector3 force, ForceMode forceMode, float externalControlDuration) |
Full control. A negative duration uses SwarmSettings.DefaultExternalControlDuration; the resulting velocity is clamped to MaxExternalVelocity. |
Targets¶
You normally don't call these — adding a SwarmTarget component registers
and unregisters automatically. Use the manager directly only for code-driven targets you don't
want to represent with a component.
| Member | Description |
|---|---|
RegisterTarget(Transform target) |
Registers a transform as a target. Returns true if it's now registered (idempotent). |
UnregisterTarget(Transform target) |
Removes a registered target. |
ClearTargets() |
Removes all targets and forces every agent to retarget. |
TryGetRegisteredTarget(int index, out Transform target) |
Reads a registered target by index. |
TryGetDesiredTargetPosition(int agentIndex, out Vector3 position) |
The point a given agent is currently steering toward (its surround slot around its target). |
RegisteredTargetCount / ActiveTargetCount / MaxActiveTargetCount |
How many targets are registered, how many are currently being chased, and the cap. |
TargetTransform / TargetPosition |
The primary (closest) target. |
Advanced¶
For deeper customization and diagnostics. Exact semantics are in IntelliSense.
| Member | Description |
|---|---|
Settings / AgentData / Grid |
Direct access to the SwarmSettings, the dense agent arrays, and the spatial hash. Read-heavy; mutate at your own risk. |
TryGetSpawnState(int agentIndex, out SwarmAgentSpawnState) |
Captures an agent's prefab + profiles + radius so you can re-spawn an identical agent later. |
Initialize() |
Allocates buffers and binds the visual manager. Called automatically on the first spawn; call it manually only to pre-allocate. |
ResetSimulation() |
Releases every agent and clears registered profiles — back to an empty swarm. |
GetOrRegisterBehaviorProfileIndex / GetOrRegisterMovementProfileIndex |
Resolve a profile asset to its runtime index (1-based; 0 means "default / none"). |
GetBehaviorProfile / GetMovementProfile / GetPersonalSpaceSettings |
Look profiles up by index. |
| LOD & dormancy counts | FullTierAgentCount, ReducedTierAgentCount, CheapTierAgentCount, DormantAgentCount — used by the stats overlay. |
Quick reference in your IDE
Key members carry a short XML summary, so hovering them in Visual Studio or Rider shows a one-line description. This page has the full detail.
Related¶
- Swarm Manager — Inspector setup and simulation tuning.
- SwarmTarget — the component-based way to add targets.
- Spawners — the built-in spawners call
TrySpawnAgentfor you. - Combat Integration — applying damage and reacting to agent death.