How the System Works

This document explains RCC's architecture at a level useful for someone who wants to use RCC effectively, not someone who wants to rebuild it from scratch. By the end you'll understand which scripts talk to which, where settings come from, and how data flows from a keyboard press all the way to the wheels turning.

The goal here is to build a mental model. Once you have one, every other document in this set becomes easier to read because you'll know where its pieces fit in.

The 30-Second Version

A typical RCC scene has three actors:

  1. An RCC_SceneManager — a singleton that tracks who the active player vehicle is.
  2. One or more RCC_CarControllerV4 components — one per vehicle in the scene.
  3. An RCC_Camera — follows whichever vehicle the SceneManager says is the player.

Each frame:

That's the whole loop. Everything else in RCC is supporting infrastructure: settings, customization, damage, AI, etc.

The Three Singletons You'll Touch

RCC uses several singletons. Most you'll never see directly, but two are important to know.

RCC_SceneManager

One per scene. Created automatically by the menu item Create → Managers → Scene Manager, or auto-spawned the first time RCC_SceneManager.Instance is accessed.

It exposes:

You never instantiate the SceneManager yourself — touching RCC_SceneManager.Instance creates one if there isn't one already. But you should still drop the Scene Manager prefab into your scene explicitly via the menu, because that way it appears in the Hierarchy where you can inspect it.

RCC_Settings

A ScriptableObject singleton (not a MonoBehaviour). The asset lives at:

Assets/RealisticCarControllerV4/Resources/RCC Assets/RCC_Settings.asset

It loads itself the first time RCC_Settings.Instance is accessed. During Play mode, RCC clones the asset into a runtime copy — this is intentional so that runtime changes (e.g., behavior switching) don't persist to the asset on disk after you exit Play mode. The first time this surprised someone it was treated as a bug; it's now an explicitly-supported design.

RCC_Settings holds:

See 21 — RCC Settings Deep Dive for every field.

Base Class: RCC_Core

Almost every RCC MonoBehaviour inherits from RCC_Core instead of directly from MonoBehaviour. RCC_Core provides two important static accessors:

It also caches a reference to the parent RCC_CarControllerV4 (CarController) — so any wheel, light, exhaust, or detachable part on a vehicle can call CarController from inside OnEnable and get the controller it belongs to. The lookup walks up the transform hierarchy on first access and caches the result. This is the most common foot-gun for new RCC code: don't re-implement parent lookup, just use CarController.

There are four classes that are not RCC_Core-derived and inherit MonoBehaviour directly: RCC_TruckTrailer, RCC_Telemetry, RCC_CheckUp (static utility), and RCC_GetBounds (static utility). These are grandfathered exceptions — don't add new ones.

The Main Vehicle Controller — RCC_CarControllerV4

This is the heart of RCC. One per vehicle. About 3,700 lines of code. It has roughly 140 serialized fields organized into the following groups:

The Inspector groups these into foldouts for clarity. See 08 — Vehicle Inspector Reference for a field-by-field walkthrough.

In code, RCC_CarControllerV4 exposes public methods like:

StartEngine();         // Ignite the engine.
KillEngine();          // Stop the engine.
ShiftToGear(int);      // Force a specific gear.
ShiftUp();             // Up one gear.
ShiftDown();           // Down one gear.
OverrideInputs(RCC_Inputs);  // Inject custom inputs (used by AI, replay, etc.).
SetCanControl(bool);   // Enable / disable player input.

Plus dozens of public properties that other systems (UI, lights, damage) read from each frame.

The Wheels — RCC_WheelCollider

Each wheel on a vehicle is a child GameObject with two components:

  1. Unity's built-in WheelCollider — provides the raycast-based suspension physics.
  2. RCC's RCC_WheelCollider — extends it with friction curves, ground detection, audio, particle dust, skidmarks, anti-roll force application, and steer/power/brake distribution flags.

The "wheel mesh transform" (the visible wheel model) is a separate transform referenced on RCC_CarControllerV4. Each frame, the controller reads the wheel collider's pose and applies it to the mesh transform so the mesh rotates and pitches realistically. This pattern is standard Unity wheel collider usage — RCC just automates the wiring.

Friction comes from the active behavior preset (when overrideBehavior is off on the wheel) or from per-wheel custom curves (when it's on). The actual WheelFrictionCurve values that Unity uses are computed in RCC_WheelCollider.Update from a combination of:

See 09 — How WheelColliders Work for the friction math in detail.

Input Flow

Input flows in one direction: from the Input System to the controller. Here's the data path:

[ Keyboard / Gamepad / Touch ]
          ↓
[ RCC_InputActions.inputactions ]  ← the Input System binding asset
          ↓
[ RCC_InputManager (singleton, Update) ]
          ↓
[ RCC_Inputs struct: throttle, brake, steer, clutch, ... ]
          ↓
[ RCC_CarControllerV4.FixedUpdate reads inputs ]
          ↓
[ WheelColliders apply torque / brake / steer ]
          ↓
[ Vehicle moves ]

On mobile, the path bypasses the Input Manager:

[ Touch UI buttons / steering wheel / joystick / gyro ]
          ↓
[ RCC_MobileButtons (static class) ]
          ↓
[ RCC_InputManager reads mobile values instead of Input System ]
          ↓
[ Same RCC_Inputs struct as before ]
          ↓
[ ... same as before ... ]

If you want to drive the car yourself (AI, replay, network), there's a third path that bypasses RCC_InputManager entirely:

[ Your code creates an RCC_Inputs struct ]
          ↓
[ Your code calls carController.OverrideInputs(myInputs) ]
          ↓
[ RCC_CarControllerV4 uses your inputs instead of polling the manager ]

See 16 — Input System and 17 — Overriding Inputs.

Events System — RCC_Events

Every interesting moment in a vehicle's life triggers a static event on RCC_Events. Examples:

This is the preferred way to integrate your game code with RCC. Subscribe to the events you care about in OnEnable, unsubscribe in OnDisable, do your custom logic in the handler. You don't need to modify any RCC scripts — your code lives alongside.

See 24 — Events System for the full list and code examples.

Cameras

The camera system is a per-player single component (RCC_Camera) that has multiple modes:

You cycle modes with the ChangeCamera input (default C) or by calling RCC.ChangeCamera() in code. RCC_Camera finds the active player vehicle from RCC_SceneManager.activePlayerVehicle automatically.

Lights

Each light on a vehicle is a child GameObject with both a Unity Light component and an RCC_Light component. RCC_Light knows whether it's a headlight, brake light, reverse light, indicator, or interior light, and updates its intensity each frame based on what the parent vehicle is doing:

RCC_Light also handles render-pipeline differences — light intensity in lumens on HDRP, in unitless on URP, etc. — so you don't need three different vehicle prefabs for the three pipelines.

Damage

Damage is embedded as a field on RCC_CarControllerV4 (not a separate component). The field is damage, of type RCC_Damage, marked [System.Serializable]. Inside it:

RCC.Repair(carController) resets all of the above instantly. See 12 — Damage System.

Customization

The Customization system is opt-in. To use it, your vehicle prefab needs an RCC_Customizer component, plus child GameObjects for each sub-manager (PaintManager, SpoilerManager, WheelManager, UpgradeManager, DecalManager, NeonManager, SirenManager, CustomizationManager). Each sub-manager reads from its corresponding Customizer_* data class (paint colors available, spoiler prefabs available, wheel prefabs available, etc.).

Loadouts persist via PlayerPrefs — when the player chooses a new paint or wheel, the change is written immediately. On vehicle spawn, the customizer reads the saved state and applies it.

See 20 — Customization.

AI

The AI driver is RCC_AICarController. It uses the same OverrideInputs() path as any other external controller — internally it computes throttle, brake, and steer values based on the next waypoint, then injects them. You don't need separate "physics for AI" — AI uses the same physics as the player.

Waypoints are placed in a scene under an RCC_AIWaypointsContainer. An AI vehicle's targetContainer field points to that container, and the AI cycles through waypoints in order. Optional RCC_AIBrakeZone triggers tell the AI to slow down for sharp corners.

See 19 — AI System.

Ground Materials

When a wheel touches a surface, RCC_WheelCollider reads the surface's PhysicMaterial (or, for Unity Terrain, the active splatmap layer at that point) and looks it up in RCC_GroundMaterials.asset. The lookup returns a GroundMaterialFrictions entry containing:

Add a new surface by adding a new entry to RCC_GroundMaterials.asset and assigning the corresponding PhysicMaterial to your collider. See 11 — Ground Physics.

Render Pipelines

RCC works on Built-in, URP, and HDRP via two compile-time defines:

Sixteen RCC scripts have code paths that branch on these defines. The differences are mostly:

The Render Pipeline Converter (Tools → BoneCracker Games → Realistic Car Controller → Render Pipeline Converter) handles all of this automatically when you switch pipelines. See 22 — URP & HDRP Conversion.

Things You Should Not Try to Change

A few patterns in RCC are intentional and important — changing them will break compatibility with users' projects and isn't necessary for any normal use case:

If you need to extend RCC, subscribe to RCC_Events from your own scripts or use the OverrideInputs() path. Don't modify the RCC scripts directly unless you're prepared to redo your changes on every update.

Where to Go Next

Now that you have the mental model, the rest of the documentation makes more sense. Some good next reads:

Or just pick whatever feature you're about to use from the Table of Contents.