Damage System

Table of Contents

RCCP includes a comprehensive damage system that supports four types of vehicle damage: mesh deformation, detachable parts, wheel damage, and light breakage. All damage types are managed through the RCCP_Damage component attached to the vehicle, and every type can be toggled independently.

When a collision occurs, RCCP calculates the impulse magnitude, converts it to a contact point, and distributes the damage across all enabled subsystems within range. The system caches original mesh data at startup so that vehicles can be fully repaired at any time.

RCCP_Damage Component

The RCCP_Damage component is the central controller for all vehicle damage. Add it to any vehicle that should support collision damage.

Key Properties

PropertyTypeDefaultDescription
automaticInstallationbooltrueWhen enabled, automatically finds all damageable meshes, detachable parts, lights, and wheels on the vehicle at startup. When disabled, you must assign each array manually in the Inspector.
damageFilterLayerMaskEverythingControls which layers can cause damage to the vehicle. Only collisions with objects on these layers will trigger damage calculations.
maximumDamagefloat0.75Maximum vertex displacement distance in meters. Limits how far any single vertex can move from its original position. Set to 0 to disable the limit.
processInactiveGameobjectsboolfalseWhether to include inactive child GameObjects when collecting meshes and parts during automatic installation.
saveNamestringVehicle nameIdentifier used for saving and loading damage data via JSON. Auto-populated from the vehicle's GameObject name.

Mesh Deformation

Mesh deformation displaces individual vertices of the vehicle's body meshes when a collision occurs. Vertices within the deformation radius of the contact point are pushed inward along the collision direction, producing realistic crumple effects.

How It Works

  1. On collision, the system converts the contact point to local space for each mesh.
  2. An octree spatial structure is used for fast nearest-vertex lookup, avoiding the cost of iterating every vertex on every collision.
  3. Vertices within deformationRadius of the contact point are displaced. Damage is stronger at the center and falls off toward the edges.
  4. Original mesh vertex positions are cached at startup so they can be restored during repair.
  5. Meshes must have Read/Write Enabled in their import settings. Non-readable meshes are automatically skipped with a console warning.

Configuration

PropertyTypeDefaultDescription
meshDeformationbooltrueMaster toggle for mesh deformation.
deformationRadiusfloat0.75Radius around the contact point (in meters) within which vertices are affected. Larger values create wider dents.
deformationMultiplierfloat1.0Scales the amount of vertex displacement. Higher values produce deeper dents from the same collision force.
recalculateNormalsboolfalseRecalculates mesh normals after deformation. Enable this if lighting looks incorrect on deformed areas. Costs some performance.
recalculateBoundsboolfalseRecalculates mesh bounds after deformation. Enable this if parts of the mesh disappear from view after heavy damage. Costs some performance.

Example: Adjusting Deformation Sensitivity


// Make the vehicle more resistant to dents
RCCP_Damage damage = vehicle.GetComponentInChildren<RCCP_Damage>();
damage.deformationMultiplier = 0.5f;  // Half the normal deformation
damage.deformationRadius = 0.5f;      // Smaller affected area
damage.maximumDamage = 0.4f;          // Limit maximum displacement

Detachable Parts (RCCP_DetachablePart)

Detachable parts are vehicle body panels (hoods, doors, bumpers, trunks) that can become loose and eventually fall off the vehicle when damaged. Each part uses a ConfigurableJoint to attach it to the vehicle body.

Setup Requirements

  1. The part must be a separate child GameObject of the vehicle with its own Rigidbody.
  2. A ConfigurableJoint is required (automatically created when adding the component via Reset()).
  3. The part's GameObject and children must be on the RCCP_DetachablePart layer.
  4. The joint's connectedBody should reference the vehicle's main Rigidbody.

Part Types

The DetachablePartType enum identifies the role of each part:

Part TypeDamage MultiplierDescription
Bumper_F1.5xFront bumper -- takes the most damage
Bumper_R1.5xRear bumper -- takes the most damage
Trunk1.2xTrunk lid
Hood1.0xEngine hood
Other1.0xAny other body panel
Door0.8xDoors -- slightly more resistant

Damage multipliers are applied when useDamageWeighting is enabled (default: true). Bumpers absorb 50% more damage per collision than hoods, while doors absorb 20% less.

Damage Lifecycle

A detachable part goes through three stages as its strength decreases:

  1. Locked -- The ConfigurableJoint motions are locked. The part is rigidly attached to the vehicle.
  2. Loose (strength <= loosePoint) -- Joint motions are unlocked to their original settings. The part wobbles and can flap in the wind (controlled by addTorqueAfterLoose).
  3. Detached (strength <= detachPoint) -- The part breaks free from the vehicle, becomes an independent physics object, and is deactivated after deactiveAfterSeconds.

Configuration

PropertyTypeDefaultDescription
partTypeDetachablePartTypeHoodIdentifies this part's role for damage weighting.
strengthfloat100Current durability. Decreases on each collision.
lockAtStartbooltrueLock the ConfigurableJoint motions at startup so the part stays firmly attached.
isDetachablebooltrueWhether this part can fully detach. If false, the part can become loose but never falls off.
loosePointint50Strength threshold below which the part becomes loose (joint unlocks).
detachPointint0Strength threshold below which the part fully detaches from the vehicle.
deactiveAfterSecondsfloat5.0Seconds after detachment before the part's GameObject is deactivated.
addTorqueAfterLooseVector3(0,0,0)Torque applied in local space when the part is loose, scaled by vehicle speed. Creates a flapping effect.
useDamageWeightingbooltrueApply the part-type-based damage multiplier.
COMTransformAuto-createdOptional center of mass override for the part's Rigidbody.

RCCP_Damage Part Settings

The RCCP_Damage component has its own toggles that control whether detachable parts receive damage at all:

PropertyTypeDefaultDescription
partDamagebooltrueMaster toggle for detachable part damage.
partDamageRadiusfloat1.0Radius around the contact point in which parts are checked for damage.
partDamageMultiplierfloat1.0Global multiplier applied to all part damage (stacks with per-part type multipliers).

Wheel Damage

Wheel damage displaces RCCP_WheelCollider positions on collision, simulating bent axles and misaligned wheels. When damage exceeds maximumDamage, wheels can optionally detach from the vehicle entirely.

Configuration

PropertyTypeDefaultDescription
wheelDamagebooltrueMaster toggle for wheel damage.
wheelDamageRadiusfloat2.0Radius around the contact point within which wheels are affected.
wheelDamageMultiplierfloat1.0Scales the amount of wheel displacement.
wheelDetachmentbooltrueWhen enabled, wheels that exceed maximumDamage displacement will detach from the vehicle.

When a wheel detaches, RCCP_WheelCollider.DetachWheel() is called, which separates the wheel model from the vehicle and creates an independent physics object.

Light Damage

Light damage reduces the strength of RCCP_Light components near the collision point. When a light's strength falls below its breakPoint, the light is marked as broken and turns off.

RCCP_Light Damage Properties

Each RCCP_Light component has its own durability settings:

PropertyTypeDefaultDescription
isBreakablebooltrueWhether this light can be broken by collisions.
strengthfloat100Current durability. Reduced by impulse * 20 on each nearby collision.
breakPointint35Strength threshold below which the light is considered broken.
brokenboolfalseRead at runtime to check if the light is broken.

RCCP_Damage Light Settings

PropertyTypeDefaultDescription
lightDamagebooltrueMaster toggle for light damage.
lightDamageRadiusfloat0.75Radius around the contact point within which lights are checked.
lightDamageMultiplierfloat1.0Scales the damage applied to lights.

Saving and Loading Damage

Damage state can be persisted between sessions using JSON serialization via PlayerPrefs.

DamageData Class

The RCCP_Damage.DamageData class stores the complete damage snapshot:

Save / Load API


RCCP_Damage damage = vehicle.GetComponentInChildren<RCCP_Damage>();

// Save current damage state
damage.Save();

// Load previously saved damage state
damage.Load();

// Delete saved damage data
damage.Delete();

The saveName property is used as the PlayerPrefs key (with _DamageData appended). Make sure each vehicle has a unique saveName if you want independent save slots.

Repairing Vehicles

There are two ways to repair a vehicle:

Using the Public API


// Repair a specific vehicle
RCCP.Repair(carController);

// Repair the current player vehicle
RCCP.Repair();

Both methods set repairNow = true on the vehicle's RCCP_Damage component, which triggers the repair process on the next frame.

What Repair Does

When repairNow is set to true:

  1. Meshes -- All deformed vertices are moved back to their original positions.
  2. Wheels -- Wheel positions and rotations are restored. Deflated tires are re-inflated via Inflate().
  3. Detachable Parts -- Each part's OnRepair() is called: strength is restored, the ConfigurableJoint is recreated if destroyed, joint properties are restored, and the part is re-enabled if it was deactivated.
  4. Lights -- Each light's OnRepair() is called: strength is restored and broken is set to false.

The repaired flag is set to true once all vertices have returned to within a small tolerance (0.002 units) of their original positions. If the repair is not complete in one frame, it continues on subsequent frames.

Multithreading

When RCCP_SceneManager.multithreadingSupported is true, mesh deformation and repair operations use Task.Run() to offload vertex calculations to background threads. This prevents frame drops on vehicles with high-polygon meshes. The system uses a CancellationTokenSource to safely cancel async operations when the component is destroyed or disabled.

When multithreading is not supported, equivalent synchronous methods (CheckRepairRaw(), CheckDamageRaw()) are used instead.

Common Issues

Damage not showing on collision

Detachable parts not falling off

Repair not working

Wheel detachment not triggering

Performance concerns with deformation

Related Topics


Support: bonecrackergames@gmail.com | www.bonecrackergames.com

Need help? See Troubleshooting