Skip to content

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.

public interface IDamageable
{
    bool CanTakeDamage { get; }
    bool ApplyDamage(float 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

  1. Add PlayerCombatTarget to your player GameObject. Set Max Health to match your game's health scale.
  2. Subscribe to OnDied to trigger your game-over or respawn flow.
  3. Add DestructibleCombatTarget to any world objects that should also be targetable (turrets, barricades).
  4. On agent prefabs where you want the player to shoot back, add SwarmAgentCombatTarget. Set Death Dissolve Duration to 0 if the VAT material has no dissolve shader.
  5. To give a turret ranged attacks, add ProjectileWeapon, assign a SwarmProjectile prefab, and set Target Mask to the agent layer.
  6. If reach calculations feel off, check Attack Profile — Target Body Radius and confirm your targets return a valid radius.