Combat Integration¶
Massive Swarm System ships a small combat layer that connects swarm attack profiles to your game objects. This page covers every contract and component involved so you can wire attack damage into your own player, enemies, and destructibles.
Overview¶
When a swarm agent lands a melee strike or contact tick, it calls ApplyDamage on whatever it finds at the target. Swarm contact hits always carry hit metadata, so the target must implement IDamageableWithContext (the projectile and sample-helper paths also accept plain IDamageable). Implement that interface or attach one of the ready-made sample components for damage to apply.
The system is intentionally thin. There is no global health manager, no required ScriptableObject, and no dependency on Unity's physics event system. Implement that interface or subclass one of the ready-made components, and attack damage flows through automatically.
Contracts¶
These interfaces live in the runtime assembly and are safe to implement in any of your own scripts.
IDamageable¶
The minimum contract for anything that can take damage.
The swarm checks CanTakeDamage before calling ApplyDamage. Return false from CanTakeDamage to make the object temporarily immune (invincibility frames, dead state, not yet spawned).
ApplyDamage should return true if damage was actually applied, false if ignored (already dead, zero damage, etc.).
IDamageableWithContext¶
Extends IDamageable with an overload that receives hit metadata.
public interface IDamageableWithContext : IDamageable
{
bool ApplyDamage(float damage, in SwarmDamageContext context);
}
Implement this when you need knockback direction, hit point, or hit normal — for example, to push a character controller away from the attacker or spawn a directional blood decal. The swarm always calls the context overload when a context is available; the plain overload is the fallback.
How the swarm picks which overload to call
SwarmDamageableExtensions.ApplyDamage checks whether the target implements IDamageableWithContext. If yes, the context overload is called. If no, the plain ApplyDamage(float) overload is called instead. You don't have to worry about this dispatch — just implement whichever interface you need.
SwarmDamageContext¶
A struct passed alongside damage that describes how the hit happened.
| Property | Type | What it contains |
|---|---|---|
Source |
UnityEngine.Object |
The agent or weapon that caused the damage |
HitPoint |
Vector3 |
World-space impact position |
HitDirection |
Vector3 |
Normalized direction the hit came from |
HitNormal |
Vector3 |
Surface normal at the hit point |
PushbackStrength |
float |
Configured push magnitude from the attack profile |
HasHitPoint |
bool |
Guards before reading HitPoint |
HasHitDirection |
bool |
Guards before reading HitDirection |
HasHitNormal |
bool |
Guards before reading HitNormal |
HasSource |
bool |
Guards before reading Source |
HasPushback |
bool |
True when PushbackStrength > 0 |
Use SwarmDamageContext.None when you need an empty context (no hit metadata). Use SwarmDamageContext.FromHit(...) to build one with all fields populated.
GetPushbackDirection(receiverPosition) is a convenience method that resolves a pushback vector from whichever hit data is available — prefers HitDirection, then falls back to the receiver-to-hit-point direction, then HitNormal. You can use this directly in a CharacterController.Move or Rigidbody.AddForce call.
ITargetable¶
Marks an object as a valid auto-target for ProjectileWeapon and other targeting systems.
public interface ITargetable
{
bool IsTargetable { get; }
Vector3 TargetPoint { get; }
Transform AimTransform { get; }
}
IsTargetable lets you gate whether a weapon can pick this object right now — return false when the object is dead or out of play. TargetPoint is the world-space position the weapon aims at; for a character it should be the body center, not the pivot. AimTransform is used by the targeting system to resolve hierarchy ownership and avoid self-hit.
Target Body Radius¶
The swarm reads how wide the target's body is from the SwarmTarget component on the target GameObject. See Targets for the body-radius source dropdown (Auto Detect / Manual) and the inspector readout.
All three sample target components (PlayerCombatTarget, DestructibleCombatTarget, SwarmAgentCombatTarget) implement ITargetable. They are damage handlers — the body radius comes from the adjacent SwarmTarget component, not from the combat target component.
DamageableBase¶
DamageableBase is an abstract MonoBehaviour that implements IDamageableWithContext for you. It manages a health pool, fires events, and calls protected virtual methods so subclasses can respond without re-implementing the core health logic.
When to use it: you want health tracking with events out of the box. Subclass it instead of implementing IDamageable directly.
When to use raw interfaces instead: you already have a health system and just need the swarm to call into it. Implement IDamageable or IDamageableWithContext directly on your existing component.
Inspector fields¶
| Field | What it controls |
|---|---|
| Max Health | Starting and maximum health value |
| Reset Health On Enable | When on, health is restored to maximum each time the component enables |
Events¶
| Event | Signature | Fires when |
|---|---|---|
OnHealthUpdated |
Action<float> |
Any health change (argument is the delta) |
OnDamageTaken |
Action<float, SwarmDamageContext> |
Damage was applied (argument is the amount taken) |
OnDied |
Action<SwarmDamageContext> |
Health reached zero |
Protected virtual methods¶
Override these in your subclass to add behavior at the right moment.
| Method | When it runs |
|---|---|
HandleDamageTaken(float, in SwarmDamageContext) |
After each damage application, before events fire |
HandleDeath(in SwarmDamageContext) |
When health first hits zero, before the OnDied event |
CanTakeDamageInternal() |
Called by CanTakeDamage to add your own immune conditions |
Do not override HandleDeath directly if you subclass CombatTargetBase
CombatTargetBase seals HandleDeath to guarantee the death VFX always spawns before your subclass logic. Override OnDeath instead — see CombatTargetBase below.
CombatTargetBase¶
CombatTargetBase extends DamageableBase and adds a pooled death-effect VFX system. All three ready-made target components inherit from it.
When to subclass it: you want death burst VFX plumbing without writing it yourself, or you want to keep your component compatible with the sample scene setup.
When to use plain DamageableBase instead: you don't need a death effect, or you're managing VFX in your own code.
Inspector fields (Death group)¶
| Field | What it controls |
|---|---|
| Death Effect Prefab | Optional pooled VFX prefab spawned when health hits zero. Leave empty to skip |
| Death Effect TTL | Seconds the effect lives before returning to the pool |
| Death Effect Anchor | Pivot — uses this GameObject's pivot (or simulation pose for swarm agents). Center — uses the world-space center of the resolved renderer's bounding box, useful when the pivot is at the character's feet |
| Death Effect Offset | World-space offset added to the resolved anchor position. Use a positive Y value to lift the burst above ground |
| Death Effect Anchor Renderer | Optional explicit renderer used when anchor mode is Center. Auto-finds the first renderer in the hierarchy if left empty |
Subclassing CombatTargetBase¶
Override OnDeath(in SwarmDamageContext context) to run your type-specific death response. The death VFX always spawns before OnDeath is called.
protected override void OnDeath(in SwarmDamageContext context)
{
// Your logic here: disable, destroy, trigger animation, etc.
}
Override GetDeathEffectPivot() to return a custom spawn position when the visual transform pivot is not where you want the burst — for example, the center of a bounding box or a simulated pose position.
Sample Components¶
All sample components live in the Samples assembly and work as-is in your scenes. They are also the reference implementations to copy when you need custom behavior.
Add them via Component → Massive Swarm System → Combat → ... or by searching the Add Component menu.
PlayerCombatTarget¶
Use this on the player character to handle swarm damage and auto-targeting by ProjectileWeapon.
Inherits from CombatTargetBase. Implements ITargetable.
Inspector fields
| Field | What it controls |
|---|---|
| Aim Point | Optional override for the aim point reported to targeting systems. Falls back to the CharacterController center, then a collider center, then the Transform pivot |
| Is Targetable | Lets you remove this object from targeting lists without disabling the component |
| Disable Game Object On Death | When on, the whole GameObject is deactivated when health reaches zero |
Body radius for reach calculations is configured on the adjacent SwarmTarget component (typically Auto Detect from the player's CharacterController / collider).
Health and death events come from DamageableBase — subscribe to OnDied, OnDamageTaken, or OnHealthUpdated in your player controller to drive UI and game state.
DestructibleCombatTarget¶
Use this on world objects that should be destroyable by swarm agents or projectiles: barricades, crates, turrets, doors.
Inherits from CombatTargetBase. Implements ITargetable.
Inspector fields
| Field | What it controls |
|---|---|
| Aim Point | Optional override for the aim point. Falls back to the collider center, then the Transform pivot |
| Is Targetable | Removes this object from targeting lists while keeping it alive |
| Death Response | Disable Game Object (default), Destroy Game Object, or None — lets the death VFX and debris remain |
| Disable Colliders On Death | When on, all Collider components on this GameObject and its children are disabled on death. Most useful with Death Response = None so agents can pass through the debris |
Body radius for reach calculations is configured on the adjacent SwarmTarget component (Auto Detect picks up the collider).
SwarmAgentCombatTarget¶
Use this when individual swarm agents should be damageable — for example, when the player fires a ProjectileWeapon at the swarm.
Inherits from CombatTargetBase. Implements ITargetable. Requires a SwarmAgent component on the same GameObject.
This component lives on the agent visual GameObject
Swarm agent visuals are pooled and reused. Do not cache a reference to SwarmAgentCombatTarget beyond the current frame — the GameObject may be returned to the pool at any moment. Subscribe to OnDied or OnDamageTaken in the same frame you resolve the component, and unsubscribe when done.
Inspector fields (Damage Response group)
| Field | What it controls |
|---|---|
| Fallback Pushback Strength | Pushback magnitude used when the damage context has a pushback direction but no explicit strength |
| Pushback Strength Multiplier | Scales all incoming pushback before it is applied to the simulation. Use to tune how far agents are knocked back |
| Knockback Duration | How long the external-force control window lasts after a hit. Negative values use the default from SwarmSettings |
| Flatten Pushback To Movement Plane | When on, the pushback direction is flattened to the XZ plane before being applied, preventing agents from launching vertically |
| Death Dissolve Duration | Seconds the VAT mesh dissolves between death and pool return. Set to 0 to skip the dissolve and despawn instantly. |
Body radius for reach calculations comes from the SwarmTarget on the same GameObject (Auto Detect picks up the agent's collider).
Death behavior. When health hits zero, the component calls SwarmManager.DespawnAgentAsDying (if dissolve duration is greater than zero) or SwarmManager.DespawnAgent (instant). The simulation slot is freed and the visual is returned to the pool.
Scripting per-agent reactions. Once you have a hit callback here, you can reach SwarmAgent on the same GameObject to apply knockback (AddImpulse) or a damage flash (PulseTint). See SwarmAgent for the full API reference and a copy-pasteable knockback recipe.
Hit detection: decide which position you mean
The agent's drawn body — and the collider on it — does not sit exactly on the simulation position. Visual Interpolation offsets it by up to one fixed step of movement, and Render Smoothing by up to half the agent's radius (for a 0.5-unit radius, roughly 5 pixels at a mid-zoom framing of about 20 pixels per world unit). This is deliberate: raycasts and collider queries hit what the player sees. Two rules follow. If your hit detection goes through the agent's collider (raycasts, projectile overlaps, triggers), it already matches the screen — leave it alone. If it computes hits from positions (distance checks, melee reach, server-side validation), read the true position via the SwarmManager per-agent API or a SwarmAgentHandle, not the visual Transform — and don't mix the two, or a body drawn half a radius away can pass a collider test and then fail a position check.
On-Hit Feedback: Damage & Heal Numbers¶
The StarterKit ships drop-on feedback helpers that react to the health events any DamageableBase fires — a red flash (DamageFlashFeedback), a world-space health bar (HealthBarDisplay), and floating damage/heal numbers (FloatingTextFeedback). Add any of them from the Scene View overlay — the Swarm Agent group for agent prefabs, the Combat Helpers group for scene targets — or from the Add Component menu.
FloatingTextFeedback¶
Shows rising damage and heal numbers over anything with a DamageableBase. It listens for OnDamageTaken and OnHealthRestored and hands them to a text manager that spawns and pools the numbers. There is no per-agent Update, so it scales to large swarms.
Add it with the overlay's Floating Combat Text button or via Component → Massive Swarm System → Combat → Floating Text Feedback. It has to sit on the same GameObject as the damageable it reads.
Inspector fields
| Field | What it controls |
|---|---|
| Damage Style | Style asset for damage numbers. Auto-fills with MSS Floating Text Damage when the component is added |
| Heal Style | Style asset for heal numbers. Auto-fills with MSS Floating Text Heal when the component is added |
| Use Hit Point | On: a damage number spawns at the weapon's hit point when the hit carried one, otherwise above the target. Off: always above the target. Heal numbers always spawn above the target |
| World Offset | Where numbers spawn relative to the target when no hit point is used (world units) |
Already on the shipped combat agents
The MSS Combat Agent prefab and the demo VAT guardians carry FloatingTextFeedback by default, so the sample swarms pop numbers the moment you shoot them. Remove the component from a prefab if you don't want them there.
Styling the numbers. A FloatingTextStyle asset sets the color, font size, how long a number lasts, how far it rises, its sideways drift, and a leading character (the shipped heal style uses +). It also holds the merge window: repeated hits on one target inside that window fold into a single climbing number instead of stacking. Duplicate a shipped style, tweak it, and drop it into the slot to restyle without touching code.
The text manager. A FloatingTextManager owns the pool and ticks every number from one Update. It creates itself the first time a number is shown, so you never place one by hand. To change the on-screen cap (64 by default, oldest recycled past it) or swap the font on every number, add an MSS Floating Text Manager to the scene and set its fields.
ProjectileWeapon¶
A self-contained turret/ranged-weapon component that finds the nearest ITargetable, rotates toward it, and fires pooled SwarmProjectile instances. Designed for the sample turrets but works on any GameObject.
Add it via Component → Massive Swarm System → Combat → Projectile Weapon.
The weapon also needs a SwarmProjectile prefab assigned. That prefab is a thin pooled MonoBehaviour that moves itself in Update and performs sphere-cast collision in FixedUpdate, calling IDamageable.ApplyDamage on the first damageable it hits.
Targeting group¶
| Field | What it controls |
|---|---|
| Muzzle | Transform used as the raycast origin and projectile spawn point. Falls back to the weapon Transform |
| Targeting Radius | Sphere radius (world units) searched each fixed frame for valid targets |
| Target Mask | Layer mask for the overlap query. Only colliders on these layers are considered |
| Target Trigger Interaction | Whether the overlap query includes trigger colliders |
| Overlap Capacity | Maximum number of colliders the overlap buffer can hold per query |
Turret Aim group¶
| Field | What it controls |
|---|---|
| Yaw Pivot | Optional Transform rotated horizontally toward the target. Falls back to the weapon Transform |
| Pitch Pivot | Optional Transform rotated vertically. Usually a child of the yaw pivot |
| Yaw Limits | Horizontal rotation limits (min and max). -180 to 180 allows full rotation |
| Pitch Limits | Vertical rotation limits (min and max), clamped to ±89 |
| Aim Turn Speed Degrees | Rotation speed in degrees per second. Set to 0 to snap instantly |
| Fire Aim Tolerance Degrees | Maximum angle between current aim and target before a shot is allowed |
Sight group¶
| Field | What it controls |
|---|---|
| Require Line Of Sight | When on, the weapon only fires if no obstructing collider is between muzzle and target |
| Sight Obstruction Mask | Layers that block line of sight. Defaults to Nothing, so no layer blocks sight until you assign one |
| Sight Radius Padding | Extra radius for sight sphere casts. Small non-zero values catch thin blockers near the path |
Sight Obstruction Mask defaults to Nothing
Out of the box, Require Line Of Sight is on but no obstruction layers are set, so walls and obstacles never block firing. Assign the relevant layers (walls, floors, cover) to get expected behaviour.
Firing group¶
| Field | What it controls |
|---|---|
| Projectile Prefab | The SwarmProjectile prefab to spawn. Required — weapon does nothing without it |
| Projectile Root | Optional parent Transform for spawned projectiles (keeps the hierarchy tidy) |
| Owner Root | Optional Transform whose hierarchy is ignored by targeting and self-hit checks. Falls back to transform.root |
| Fires Per Second | Fire rate |
| Damage | Damage applied to the first damageable hit by each projectile |
| Projectile Pushback Strength | Pushback strength passed to SwarmDamageContext.FromHit on impact |
| Projectile Speed | Travel speed in world units per second |
| Projectile Lifetime | Seconds before an unfired projectile despawns itself |
| Projectile Hit Radius | Sphere-cast radius for collision detection. Zero uses a pure raycast |
| Projectile Collision Mask | Layers the projectile collides with |
| Projectile Trigger Interaction | Whether projectile collision includes trigger colliders |
| Projectiles Per Shot | Number of projectiles launched each shot. Above 1, the extra projectiles fan out across the multi-shot spread |
| Multi Shot Spread Degrees | Total fan angle spread across the projectiles when more than one fires per shot |
Pool sizes (initial count and growth cap) are configured on the SwarmPoolManager component under its Shared Pool Defaults group, not on this component.
Choosing What to Use¶
| Your situation | What to add |
|---|---|
| Player character needs health + swarm damage + auto-targeting | PlayerCombatTarget |
| World prop needs health + swarm damage + auto-targeting | DestructibleCombatTarget |
| Individual agents need to take player damage | SwarmAgentCombatTarget on the agent prefab |
| You want a ready-made turret that fires at agents | ProjectileWeapon + a SwarmProjectile prefab |
| You want floating damage / heal numbers over a target | FloatingTextFeedback (one click from the overlay; already on the shipped combat agents) |
| You have your own health system and just need swarm damage to call into it | Implement IDamageable (or IDamageableWithContext) directly |
| You want health tracking with events but no VFX | Subclass DamageableBase |
| You want health tracking + death VFX | Subclass CombatTargetBase and override OnDeath |
For the reach formula that governs when an agent can land a hit, see Attack Profile — How Reach Is Measured.
Sample Helpers¶
Lightweight components for adding melee and contact damage to non-swarm GameObjects. They use the same IDamageable contract as the rest of the combat layer.
Add them via Component → Massive Swarm System → Combat → ... or by searching the Add Component menu.
Rotating Weapon¶
A sweeping melee weapon that rotates between two angles, performs a sphere-cast + overlap-sphere pass along the arc, and calls IDamageable.ApplyDamage on anything it touches. Each activation hits a given target at most once, regardless of how many frames the sweep overlaps it.
Use this for enemies or hazards that need a procedural swing attack — spinning blades, arm swings, area denials.
Timing
| Field | What it controls |
|---|---|
| Swing Duration | How long one full sweep takes (start angle to end angle) |
| Delay Between Activations | Idle time after a swing completes before the next one starts |
| Initial Delay | Wait before the very first swing after the component enables |
Rotation
| Field | What it controls |
|---|---|
| Swing Plane | XZ rotates the weapon around the Y axis (top-down sweep); XY rotates around the Z axis (side-on sweep) |
| Start Angle Degrees | Local rotation angle at the beginning of the sweep |
| End Angle Degrees | Local rotation angle at the end of the sweep |
Hit Sphere
| Field | What it controls |
|---|---|
| Hit Sphere Distance From Base | How far along the weapon the hit sphere sits, in world units |
| Hit Sphere Radius | Radius of the hit sphere. Scaled by the GameObject's lossy scale at runtime |
| Query Capacity | Maximum colliders processed per sweep or overlap query |
| Collision Mask | Layers the swing physically checks. Defaults to Everything, so walls and props can block targets behind them |
| Target Mask | Layers eligible to take damage. Colliders outside this mask can still block the swing through Collision Mask |
| Query Trigger Interaction | Whether the query includes trigger colliders |
Damage
| Field | What it controls |
|---|---|
| Damage | Flat damage passed to IDamageable.ApplyDamage |
| Pushback Strength | Written into SwarmDamageContext for receivers that use it |
| Owner Root | Optional transform excluded from hit detection and written as the damage instigator. Falls back to transform.root if not set |
Visuals
| Field | What it controls |
|---|---|
| Visual Root | Optional child object toggled on/off during the swing. When not set, the component enables and disables child Renderer components instead |
| Use Scale Tween | When on, the weapon scales in at swing start and out at swing end |
| Scale Tween Duration | Duration of the scale-in and scale-out phases |
Debug
| Field | What it controls |
|---|---|
| Draw Debug Gizmos | Draws the swing arc and hit sphere in the Scene view. On by default |
Touch Damage Source¶
Applies damage to any IDamageable that enters its trigger collider. Requires a trigger collider on the same GameObject. Adds a kinematic Rigidbody automatically at runtime if none is present.
Use this for hazards or enemies that damage on contact: lava zones, spinning saws, enemy bodies.
Damage
| Field | What it controls |
|---|---|
| Damage | Amount applied per damage event |
| Reapply Delay | Seconds between re-applications while the target stays inside. Set to 0 or below to hit once per continuous touch |
| Pushback Strength | Written into SwarmDamageContext for receivers that use it |
| Owner Root | Optional transform excluded from self-overlap. Falls back to transform.root if not set |
Target Filter
| Field | What it controls |
|---|---|
| Target Filter Mode | None — hit everything; Tag — require matching tag; Layer — require matching layer; Tag And Layer — both must match; Tag Or Layer — either must match |
| Required Tag | Tag compared when the filter mode includes Tag. Empty by default — set a tag before choosing a Tag-inclusive filter mode, or no target will match |
| Target Layers | Layer mask compared when the filter mode includes Layer |
Required Tag must exist in your project
If Required Tag names a tag that has not been defined in your project's Tag Manager, Unity throws a runtime exception. The component catches it and logs an error once, but no damage is applied until you fix the tag.
Quickstart — wire up damage in this order
- Add
PlayerCombatTargetto your player GameObject. Set Max Health to match your game's health scale. - Subscribe to
OnDiedto trigger your game-over or respawn flow. - Add
DestructibleCombatTargetto any world objects that should also be targetable (turrets, barricades). - On agent prefabs where you want the player to shoot back, add
SwarmAgentCombatTarget. Set Death Dissolve Duration to0if the VAT material has no dissolve shader. - To give a turret ranged attacks, add
ProjectileWeapon, assign aSwarmProjectileprefab, and set Target Mask to the agent layer. - For damage and heal numbers over a target, add
FloatingTextFeedback(the agent prefabs already have it). The styles fill in on their own. - If reach calculations feel off, check Attack Profile — Target Body Radius and confirm your targets return a valid radius.