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. Instanced VAT agents ignore this field and fall back to instant despawn |
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.
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 |
| Min / Max Yaw Degrees | Horizontal rotation limits. -180 to 180 for full rotation |
| Min / Max Pitch Degrees | Vertical rotation limits, clamped internally 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 |
Pooling group¶
| Field | What it controls |
|---|---|
| Initial Pool Size | Projectile instances created at startup |
| Max Pool Size | Pool growth cap |
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 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 |
Local 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 |
Local 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 |
| Target Mask | Layer mask for the hit query |
| 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 |
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. Defaults to Player |
| 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. - If reach calculations feel off, check Attack Profile — Target Body Radius and confirm your targets return a valid radius.