Damage System
RCC has a comprehensive damage system that handles mesh deformation, detachable body parts, wheel damage, and broken lights. This document explains how each piece works, how to configure it, and how to extend it for your own gameplay (e.g., destruction derbies, demolition modes, vehicular combat).
The damage system is embedded into RCC_CarControllerV4 rather than being a separate component — the field is damage of type RCC_Damage, marked [System.Serializable]. This is by design and is the source of one common confusion: you can't add a "Damage" component, because it's already part of the controller.
What Damage Affects
When a vehicle takes damage, four visible things change:
- Mesh deformation — vertices on the body push inward at collision contact points.
- Detachable parts — hoods, doors, bumpers can break off and become physics objects.
- Wheel damage — wheels can shift out of alignment or pop off entirely.
- Light damage — bulbs stop emitting light.
Each is configurable independently. You can enable all of them, or just the parts you want.
Enabling Damage
The top-level toggle is Use Damage in the RCC_Damage section of the Inspector. When off, no damage is processed (the vehicle is invincible). When on, damage accumulates from collisions.
By default this is on. To make a vehicle invincible (e.g., a tutorial mode or a "ghost car"), uncheck it.
Damage Sensitivity
Three fields control how easily the vehicle takes damage:
- Damage Multiplier — global scalar. Default 1.0. Higher = more damage per collision.
- Max Damage — the cap on accumulated damage. Once reached, mesh deformation stops at the cap. Default 100.
- Use Mesh Deformation — if false, only part / wheel / light damage processes; mesh stays intact.
For a destruction derby game, increase Damage Multiplier to 2–3. For a casual driving game where minor scrapes shouldn't be visible, decrease it to 0.5.
Mesh Deformation
When the vehicle hits something hard enough, the affected body mesh has its vertices pushed inward from the collision point. The deformation depth scales with collision force.
How It Works
- On
OnCollisionEnter, the controller reads eachContactPoint. - For each contact, it builds a query: "find every vertex within deformation radius of this point."
- The query is served by an
RCC_Octree— a spatial data structure built from the body mesh's vertices at startup. Octree queries are O(log N) instead of O(N), which matters for high-poly cars. - Found vertices are displaced inward along the collision normal, scaled by force and damage multiplier.
- The mesh is marked dirty and Unity re-uploads it to the GPU.
Configuration
| Field | What It Does |
|---|---|
| Use Mesh Deformation | Enable deformation. |
| Damage Radius | How wide the deformation effect is per contact point. |
| Deformation Vertices Damage Multiplier | Per-vertex displacement scalar. |
| Original Meshes Pose | A pre-recorded list of rest positions for all body vertices. Recreated by clicking Recalculate Original Meshes. |
"Recalculate Original Meshes"
If you change the vehicle's body mesh, you must regenerate the octree and the rest pose. Click Recalculate Original Meshes in the damage section. This is also necessary after attaching new detachable parts or changing the vehicle's hierarchy.
Mesh Deformation Caveats
- Only child meshes of the vehicle that have a
MeshFilterand aMeshRendererget deformation. Skinned meshes (SkinnedMeshRenderer) are not deformed — this is a Unity limitation, not RCC's. - Deformation is non-reversible by default, but
RCC.Repair()resets all vertices to their rest pose. To repair without repair, setdamage.repairNow = true. - Mesh deformation has a performance cost proportional to the polygon count of the deformed mesh. Very high-poly meshes (50k+ verts) may stutter on mobile.
Detachable Parts
A "detachable part" is a body part (hood, door, bumper, mirror) that can break off the vehicle on enough damage and become a separate physics object.
Setup
- Create the body part as a separate child GameObject under the vehicle root.
- Position it at the rest location.
- Add a
Rigidbodycomponent (keep it kinematic for now — the controller will un-kinematic it on break). - Add a
Collider(BoxCollider or MeshCollider). - Add a
ConfigurableJointcomponent connecting it to the vehicle's Rigidbody. - Add an
RCC_DetachablePartcomponent.
The ConfigurableJoint is what holds the part to the body — when its breakForce is exceeded, Unity breaks the joint and the part becomes free.
RCC_DetachablePart Configuration
- Joint Type — Hood, Trunk, Door, Bumper, etc. Affects which animation plays during damage.
- Break Force — How much force (N) the joint can withstand before breaking. Default 6000.
- Break Torque — How much torque (Nm) before breaking.
- Strength — Multiplier on the part's HP. Higher = more resistant.
When the part breaks, the joint is removed, the rigidbody becomes non-kinematic, and gravity takes over.
Reattaching Parts on Repair
RCC.Repair(carController) re-parents broken parts back to the vehicle, restores their kinematic state, and recreates the joint. The part returns to its rest pose.
Built-in Detachable Part Examples
Open one of the demo vehicle prefabs (e.g., M3_E46_New.prefab) and look at its children. You'll find pre-configured detachable parts for the hood and bumpers. Use these as a template when adding your own.
Wheel Damage
Wheels can shift out of alignment or pop off entirely.
How It Works
When the wheel takes a strong sideways impact:
- The wheel's pivot transform shifts away from its rest position.
- The wheel collider remains at its original position (the visible wheel pivots away from the physics wheel).
- At high damage, the wheel is "popped off" — the wheel mesh is detached and falls as a rigidbody.
Configuration
- Use Wheel Damage — Enable wheel damage.
- Wheel Damage Radius — How far from the wheel a collision counts as wheel damage.
- Wheel Damage Multiplier — How easily the wheel takes damage.
- Wheel Detach Multiplier — How quickly the wheel pops off vs just shifting.
Repair
RCC.Repair() resets each wheel transform to its rest pose and reattaches any popped-off wheels.
Light Damage
When the vehicle is damaged enough at the front (where headlights are) or back (brake/reverse lights), individual lights can be marked broken and stop emitting.
How It Works
The RCC_Damage system tracks each RCC_Light component on the vehicle and assigns it a damage score based on impacts in its vicinity. When the score exceeds a threshold, the light's intensity is forced to 0 and a small visible "broken bulb" effect plays (configured in the light's prefab — see 14 — Lights System).
Configuration
- Use Light Damage — Enable light damage.
- Light Damage Radius — How far from a light a collision counts.
- Light Damage Multiplier — How easily lights break.
Repair
RCC.Repair() restores all lights to their original intensity.
Repairing
There are three ways to repair a vehicle:
1. Repair Now (Direct)
In code:
carController.damage.repairNow = true;
This triggers a full repair in the next FixedUpdate.
2. Public API
RCC.Repair(carController); // Repair a specific vehicle.
RCC.Repair(); // Repair the active player vehicle.
Both call the same code path.
3. Repair Station Prefab
Drop the RCC_RepairStation prefab into your scene. It's a trigger volume — when the player drives into it, the vehicle repairs automatically. You can edit the visual appearance of the trigger volume to look like a gas-station-style repair booth, a wrench icon on the ground, or whatever fits your art style.
The repair station's logic is in Scripts/Others/RCC_RepairStation.cs — a few dozen lines you can adapt for any custom repair logic (e.g., charge the player money on repair).
Damage Events
Subscribe to collision events through RCC_Events:
using UnityEngine;
public class DamageLogger : MonoBehaviour {
void OnEnable() { RCC_Events.OnRCCPlayerCollision += HandleCollision; }
void OnDisable() { RCC_Events.OnRCCPlayerCollision -= HandleCollision; }
void HandleCollision(RCC_CarControllerV4 vehicle, Collision collision) {
float impactSpeed = collision.relativeVelocity.magnitude;
Debug.Log($"Crashed at {impactSpeed:F1} m/s into {collision.gameObject.name}");
// Subtract score, play sound, etc.
}
}
The event fires inside RCC_CarControllerV4.OnCollisionEnter. The collision parameter is Unity's standard Collision struct, so you have access to contact points, relative velocity, the other collider, etc.
Damage State Queries
In your own game code, you may want to know whether the player has taken too much damage (e.g., to fail a mission, or to disable the vehicle until repaired):
RCC_CarControllerV4 vehicle = RCC_SceneManager.Instance.activePlayerVehicle;
if (vehicle != null) {
float currentDamage = vehicle.damage.totalDamage;
float maxDamage = vehicle.damage.maxDamage;
float damagePercent = currentDamage / maxDamage;
if (damagePercent >= 1.0f) {
// Vehicle is fully damaged.
}
}
(Field names may vary slightly — check RCC_Damage.cs for the actual field your version exposes.)
Tuning Damage Feel
The damage system has many knobs. Here are the most useful tuning levers in order of impact:
- Damage Multiplier — overall sensitivity. Adjust this first.
- Damage Radius — how local each impact's deformation is. Larger = wider dents.
- Detachable Part Break Force — when parts come off. Lower for action games, higher for sim.
- Wheel Damage Multiplier — how easily wheels go out of alignment.
- Light Damage Multiplier — how easily lights break.
For a destruction derby game, set:
- Damage Multiplier: 2.0–3.0
- Detachable Break Force: 3000 (low — parts fly off easily)
- Wheel Detach Multiplier: 2.0 (wheels pop off on big hits)
For a casual driving game, set:
- Damage Multiplier: 0.3–0.5
- Detachable Break Force: 12000 (high — parts rarely break)
- Wheel Detach Multiplier: 0.5 (wheels almost never pop off)
For a simulator, leave defaults — they're tuned for realistic feel.
Performance Considerations
Damage processing has two costs:
- Octree build at startup — proportional to total vehicle vertices. ~10 ms for a 10k-vertex car. One-time only.
- Per-collision deformation — proportional to vertices within damage radius. Usually negligible (<1 ms).
Detachable parts and broken wheels create runtime rigidbodies — Unity-default physics objects. A vehicle with 5 broken parts is roughly equivalent in cost to a vehicle with 5 child rigidbodies, which is fine on desktop and acceptable on mobile.
If you have many damaged vehicles in a scene (e.g., a wrecking yard environment), consider disabling damage on background vehicles and only enabling it on the active player + AI opponents.
Common Damage Issues
"Mesh deformation doesn't work"
Most common: the body mesh is a SkinnedMeshRenderer instead of a MeshRenderer. Skinned meshes can't be deformed by RCC. Convert the body to a static mesh (right-click the mesh asset → Re-Import with skinning disabled).
Second most common: Recalculate Original Meshes hasn't been clicked since the prefab was modified. Click it and try again.
"Detachable parts fall off too easily / too hard"
Adjust Break Force on each ConfigurableJoint. Test at intentional impact speeds (e.g., drive into a wall at 30 km/h) until breakaway threshold feels right.
"The wheels look broken after a small bump"
Wheel Damage Multiplier is too high. Lower it.
"I clicked Repair but the parts didn't come back"
The detachable parts need to be children of the vehicle when Repair is called. If a part has been completely destroyed (e.g., its GameObject was destroyed by an explosion in your own code), it can't be restored. The repair only resets parts that are still in the scene.
Next Steps
- 14 — Lights System — light configuration including damage.
- 24 — Events System — subscribing to collision events.
- 23 — Scripting API —
RCC.Repair()and related calls.