| 1 |
Calcs
(
aka
the
Code,
Math
and
You:
A
Beginner’s
Guide)
|
1 |
Collision
Calcs
(
aka
the
Code,
Math
and
You:
A
Beginner’s
Guide)
|
| 2 |
\n
|
2 |
\n
|
| 3 |
1. Unit-vs-Unit Collision
|
3 |
1. Unit-vs-Unit Collision
|
| 4 |
\n
|
4 |
\n
|
| 5 |
Handled by the DoCollisionDamage() function, triggered when weaponDefID == -3 and an attackerID is present.
|
5 |
Handled by the DoCollisionDamage() function, triggered when weaponDefID == -3 and an attackerID is present.
|
| 6 |
\n
|
6 |
\n
|
| 7 |
Step 1, Speed check: Collision damage only activates if either unit's speed exceeds UNIT_UNIT_SPEED (5.5 elmos/frame).
|
7 |
Step 1, Speed check: Collision damage only activates if either unit's speed exceeds UNIT_UNIT_SPEED (5.5 elmos/frame).
|
| 8 |
\n
|
8 |
\n
|
| 9 |
Step 2, Relative speed: The relative velocity between the two units is calculated as:
|
9 |
Step 2, Relative speed: The relative velocity between the two units is calculated as:
|
| 10 |
\n
|
10 |
\n
|
| 11 |
relativeSpeed = sqrt((oVx-myVx)² + (oVy-myVy)² + (oVz-myVz)²)
|
11 |
relativeSpeed = sqrt((oVx-myVx)² + (oVy-myVy)² + (oVz-myVz)²)
|
| 12 |
\n
|
12 |
\n
|
| 13 |
Step 3, Damage per unit: Each unit's damage is calculated using LocalSpeedToDamage():
|
13 |
Step 3, Damage per unit: Each unit's damage is calculated using LocalSpeedToDamage():
|
| 14 |
\n
|
14 |
\n
|
| 15 |
if relativeSpeed > velocityDamageThreshold (3):
|
15 |
if relativeSpeed > velocityDamageThreshold (3):
|
| 16 |
damage = (relativeSpeed - 3) × (mass × 0.6)
|
16 |
damage = (relativeSpeed - 3) × (mass × 0.6)
|
| 17 |
\n
|
17 |
\n
|
| 18 |
Buildings get a ×10 multiplier on their velocityDamageScale since they're treated as far more massive.
|
18 |
Buildings get a ×10 multiplier on their velocityDamageScale since they're treated as far more massive.
|
| 19 |
\n
|
19 |
\n
|
| 20 |
Step 4, Final damage dealt: The game deals the lesser of the two units' computed damages, multiplied by UNIT_UNIT_DAMAGE_FACTOR (0.8) so the smaller/lighter unit sets the damage ceiling. Both units take this same amount.
|
20 |
Step 4, Final damage dealt: The game deals the lesser of the two units' computed damages, multiplied by UNIT_UNIT_DAMAGE_FACTOR (0.8) so the smaller/lighter unit sets the damage ceiling. Both units take this same amount.
|
| 21 |
\n
|
21 |
\n
|
| 22 |
Step 5, Multipliers & immunity: The final damage is scaled by each unit's collisionDamageMult (set per-unit by other gadgets). Units can be immune (e.g. during jump/teleport), and allied units are protected from "no-ally-damage" flags.
|
22 |
Step 5, Multipliers & immunity: The final damage is scaled by each unit's collisionDamageMult (set per-unit by other gadgets). Units can be immune (e.g. during jump/teleport), and allied units are protected from "no-ally-damage" flags.
|
| 23 |
\n
|
23 |
\n
|
| 24 |
Step 6, Velocity correction: After collision, both units' velocities are blended toward a shared momentum-conserving average (a weighted sum based on their masses), simulating an inelastic collision. GitHub
|
24 |
Step 6, Velocity correction: After collision, both units' velocities are blended toward a shared momentum-conserving average (a weighted sum based on their masses), simulating an inelastic collision. GitHub
|
| 25 |
\n
|
25 |
\n
|
| 26 |
2. Unit-vs-Ground Collision (Fall Damage)
|
26 |
2. Unit-vs-Ground Collision (Fall Damage)
|
| 27 |
\n
|
27 |
\n
|
| 28 |
Triggered when weaponDefID == -2 with no attacker. This is the classic "fall damage."
|
28 |
Triggered when weaponDefID == -2 with no attacker. This is the classic "fall damage."
|
| 29 |
\n
|
29 |
\n
|
| 30 |
Step 1, Decompose velocity into normal and tangent: The unit's velocity is split into a component normal to the terrain surface and a tangential component (sliding along it).
|
30 |
Step 1, Decompose velocity into normal and tangent: The unit's velocity is split into a component normal to the terrain surface and a tangential component (sliding along it).
|
| 31 |
\n
|
31 |
\n
|
| 32 |
Step 2, Bounce physics: The normal component is reflected and scaled by elasticity (default 0.3), and the tangential component is scaled by friction (default 0.8), then an impulse is applied to simulate the bounce.
|
32 |
Step 2, Bounce physics: The normal component is reflected and scaled by elasticity (default 0.3), and the tangential component is scaled by friction (default 0.8), then an impulse is applied to simulate the bounce.
|
| 33 |
\n
|
33 |
\n
|
| 34 |
Step 3, Damage speed calculation:
|
34 |
Step 3, Damage speed calculation:
|
| 35 |
damageSpeed = magnitude of (normal + tangent × TANGENT_DAMAGE)
|
35 |
damageSpeed = magnitude of (normal + tangent × TANGENT_DAMAGE)
|
| 36 |
where TANGENT_DAMAGE = 0.5, so sliding impacts count for half.
|
36 |
where TANGENT_DAMAGE = 0.5, so sliding impacts count for half.
|
| 37 |
\n
|
37 |
\n
|
| 38 |
Step 4, Convert speed to damage (same LocalSpeedToDamage() as above):
|
38 |
Step 4, Convert speed to damage (same LocalSpeedToDamage() as above):
|
| 39 |
if damageSpeed > 3:
|
39 |
if damageSpeed > 3:
|
| 40 |
damage = (damageSpeed - 3) × (mass × 0.6)
|
40 |
damage = (damageSpeed - 3) × (mass × 0.6)
|
| 41 |
\n
|
41 |
\n
|
| 42 |
Step 5, Out-of-map bonus damage: If the unit is outside the map boundaries, additional damage is added proportional to how far out of bounds the unit is, scaled by unit.health / 800.
|
42 |
Step 5, Out-of-map bonus damage: If the unit is outside the map boundaries, additional damage is added proportional to how far out of bounds the unit is, scaled by unit.health / 800.
|
| 43 |
\n
|
43 |
\n
|
| 44 |
Step 6, Multiplier applied: Final damage × collisionDamageMult[unitID] (or 1 if unset).
|
44 |
Step 6, Multiplier applied: Final damage × collisionDamageMult[unitID] (or 1 if unset).
|
| 45 |
\n
|
45 |
\n
|
| 46 |
3. Unit-vs-Wreck/Feature Collision
|
46 |
3. Unit-vs-Wreck/Feature Collision
|
| 47 |
\n
|
47 |
\n
|
| 48 |
Triggered when weaponDefID == -3 and
|
48 |
Triggered when weaponDefID == -3 and
|
| 49 |
attackerID == nil (no unit attacker — a feature like debris).
|
49 |
attackerID == nil (no unit attacker — a feature like debris).
|
| 50 |
\n
|
50 |
\n
|
| 51 |
The engine's native damage value is taken and multiplied by DEBRIS_SPRING_DAMAGE_MULTIPLIER = 10 (described in the code as "tweaked arbitrarily"), then scaled by collisionDamageMult. The unit also gets a velocity-scaling impulse of 0.3 (i.e. it loses 70% of its speed).
|
51 |
The engine's native damage value is taken and multiplied by DEBRIS_SPRING_DAMAGE_MULTIPLIER = 10 (described in the code as "tweaked arbitrarily"), then scaled by collisionDamageMult. The unit also gets a velocity-scaling impulse of 0.3 (i.e. it loses 70% of its speed).
|
| 52 |
\n
|
52 |
\n
|
| 53 |
Note: Feature collisions still use the native engine value as a base, unlike unit-unit and ground collisions which are calculated entirely from scratch.
|
53 |
Note: Feature collisions still use the native engine value as a base, unlike unit-unit and ground collisions which are calculated entirely from scratch.
|
| 54 |
\n
|
54 |
\n
|