Skip to content

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.