Overriding Inputs
The Override Inputs system lets you feed custom inputs into a vehicle from your own code, completely bypassing the player input system. This is how AI vehicles drive themselves, how replay playback works, how networked multiplayer feeds remote vehicle state, and how scripted cutscenes can move a car along a predetermined path.
This document explains the override system, shows a complete working example, and lists the common use cases.
When to Use Override Inputs
Use override inputs when:
- You're building an AI driver (and not using RCC's built-in
RCC_AICarController). - You're playing back a recorded replay of past driver inputs.
- You're driving a networked vehicle based on inputs received from the network.
- You're running a scripted cinematic where the car must follow a precise path.
- You're building a driving school where the system temporarily takes over.
Don't use it for normal player input — for that, the Input Manager path is simpler and free.
How It Works
Two flags on RCC_CarControllerV4 control the input source:
overrideInputs— whentrue, the controller ignoresRCC_InputManagerand uses the inputs supplied viaOverrideInputs(RCC_Inputs)each frame.externalController— a related flag set by AI controllers. Whentrue, the controller assumes an external script is driving it (used to suppress auto-start-engine on awake).
The flow:
- Your script creates a new
RCC_Inputsstruct each frame. - Your script fills in
throttleInput,brakeInput,steerInput, etc. - Your script calls
carController.OverrideInputs(myInputs). - The controller uses your values instead of polling the InputManager.
- The vehicle moves according to your inputs.
If you don't call OverrideInputs for a frame (e.g., your AI script returns early), the controller uses the last override inputs you sent — so don't worry about calling it every single frame, but do update at least every few frames or the car will drive on stale data.
Minimal Example — Drive in a Circle
using UnityEngine;
public class DriveInCircle : MonoBehaviour {
public RCC_CarControllerV4 carController;
void Start() {
carController.overrideInputs = true;
}
void Update() {
RCC_Inputs inputs = new RCC_Inputs();
inputs.throttleInput = 0.4f;
inputs.steerInput = 0.5f; // constant right turn
inputs.brakeInput = 0f;
inputs.handbrakeInput = 0f;
inputs.clutchInput = 0f;
carController.OverrideInputs(inputs);
}
}
Attach this to any GameObject, drag a vehicle into the carController field, press Play, and the car drives in a circle.
Realistic Example — Follow a Target Point
A more useful pattern is steering toward a target:
using UnityEngine;
public class DriveToTarget : MonoBehaviour {
public RCC_CarControllerV4 carController;
public Transform target;
public float desiredSpeed = 80f; // km/h
void Start() {
carController.overrideInputs = true;
}
void Update() {
if (target == null) return;
RCC_Inputs inputs = new RCC_Inputs();
// Compute the steering direction.
Vector3 toTarget = target.position - carController.transform.position;
Vector3 localToTarget = carController.transform.InverseTransformDirection(toTarget.normalized);
// localToTarget.x is positive if target is to our right, negative if left.
inputs.steerInput = Mathf.Clamp(localToTarget.x * 2f, -1f, 1f);
// Cruise control — accelerate or brake to maintain desiredSpeed.
if (carController.speed < desiredSpeed) {
inputs.throttleInput = 1f;
inputs.brakeInput = 0f;
} else {
inputs.throttleInput = 0f;
inputs.brakeInput = 0.5f;
}
carController.OverrideInputs(inputs);
}
}
This is the kernel of how AI drivers work. Add more sophistication on top:
- Look ahead by several seconds and compute steering based on the future position of the target.
- Apply a "blend" steering — don't snap to full lock, ramp into it.
- Slow down for sharp turns by reading the angle to the target.
- Avoid obstacles via raycasts.
The built-in RCC_AICarController does all of this and more — see 19 — AI System for the full feature list. Use it unless you need a behavior that the AI doesn't support.
Network Multiplayer Pattern
For networked vehicles where the remote player's inputs arrive over the network:
using UnityEngine;
public class NetworkedVehicle : MonoBehaviour {
public RCC_CarControllerV4 carController;
public bool isLocalPlayer;
// These would be filled by your network library (Netcode, Mirror, Photon Fusion, etc.).
[SerializeField] private float networkThrottle;
[SerializeField] private float networkBrake;
[SerializeField] private float networkSteer;
[SerializeField] private float networkHandbrake;
void Start() {
if (isLocalPlayer) {
// This is OUR car — read player input normally.
carController.overrideInputs = false;
} else {
// This is someone else's car — feed inputs from the network.
carController.overrideInputs = true;
}
}
void Update() {
if (!isLocalPlayer) {
RCC_Inputs inputs = new RCC_Inputs();
inputs.throttleInput = networkThrottle;
inputs.brakeInput = networkBrake;
inputs.steerInput = networkSteer;
inputs.handbrakeInput = networkHandbrake;
carController.OverrideInputs(inputs);
}
// For local player, you'd also push current inputs over the network here:
if (isLocalPlayer) {
RCC_Inputs current = RCC_InputManager.Instance.GetInputs();
// Send current.throttleInput, current.brakeInput, etc. to the server.
}
}
}
This is the building block for multiplayer. The network library handles the actual data sync — your job is to feed RCC the data once it arrives.
For best results in networked games, you'll also want to sync the vehicle's transform (position + rotation) and rigidbody state (velocity + angular velocity) — input-only sync drifts over time because physics simulations aren't deterministic across clients. See your network library's docs for transform syncing patterns.
Replay Pattern
RCC ships with a basic recorder/replayer in Scripts/RCC_Recorder.cs. The pattern is:
// During recording, save inputs every frame:
RCC_Inputs current = carController.GetInputs();
recordedInputs.Add(current);
// During replay, feed saved inputs back:
carController.overrideInputs = true;
foreach (var savedInput in recordedInputs) {
carController.OverrideInputs(savedInput);
yield return null; // wait one frame
}
The included recorder also records position and rotation per frame for "ghost" / "rewind" gameplay. See RCC_Recorder.cs for the full implementation.
To start/stop recording from code: RCC.StartStopRecord(). To start/stop replay: RCC.StartStopReplay().
Scripted Cinematic Pattern
For a "the car drives itself for 5 seconds" cutscene:
using System.Collections;
using UnityEngine;
public class CinematicDrive : MonoBehaviour {
public RCC_CarControllerV4 carController;
public IEnumerator DriveStraightFor(float seconds) {
carController.overrideInputs = true;
RCC_Inputs inputs = new RCC_Inputs { throttleInput = 0.5f };
float t = 0f;
while (t < seconds) {
carController.OverrideInputs(inputs);
t += Time.deltaTime;
yield return null;
}
// Restore player control.
carController.overrideInputs = false;
}
}
Call StartCoroutine(DriveStraightFor(5f)) from anywhere to make the car drive itself for 5 seconds.
Combining Override With Player Input
You can blend player input with override input — e.g., for "assisted driving" where the AI nudges the player toward the racing line:
void Update() {
RCC_Inputs playerInputs = RCC_InputManager.Instance.GetInputs();
RCC_Inputs assistInputs = ComputeAssistInputs();
RCC_Inputs blended = new RCC_Inputs();
blended.throttleInput = playerInputs.throttleInput; // player controls throttle
blended.brakeInput = playerInputs.brakeInput; // player controls brake
blended.steerInput = Mathf.Lerp(playerInputs.steerInput, assistInputs.steerInput, 0.3f); // blend steering
carController.OverrideInputs(blended);
}
For this pattern to work, overrideInputs must stay true — otherwise the controller polls the InputManager directly.
Disabling Override
To return control to the player:
carController.overrideInputs = false;
The controller immediately starts reading from the InputManager again on the next FixedUpdate.
When OverrideInputs Doesn't Fully Take Effect
A few things keep working even when override is active:
- Camera inputs —
orbitX,orbitY,scroll. The camera still reads these from the player. To control the camera from override, fill these fields in your RCC_Inputs struct. - Engine ignition —
RunEngineAtAwakeandengineRunningstate aren't part of the inputs. To start/stop the engine programmatically, callcarController.StartEngine()/carController.KillEngine(). - Gear shifts via inputs — gear input has special handling. To force a gear, call
carController.ShiftToGear(int)directly.
For most uses, just filling throttle/brake/steer/handbrake/clutch is enough.
Common Pitfalls
"I set override = true but the car still responds to player input"
Make sure you're calling OverrideInputs() every frame after setting the flag. If you only set the flag without supplying inputs, the controller uses the inputs from before override was enabled — which were the player's last inputs.
"I want override only sometimes, but the car keeps drifting on stale inputs"
Whenever you stop driving the car via override, call carController.OverrideInputs(new RCC_Inputs()) once to zero everything out, then set overrideInputs = false.
"Override doesn't engage from a parked state"
If the engine isn't running, the override won't move the car. Make sure to call carController.StartEngine() before driving via override.
"Override breaks when I switch behaviors"
It shouldn't — behavior switching doesn't affect override state. If you see this, file a bug.
See Also
- 19 — AI System — the built-in AI uses Override Inputs internally.
- 23 — Scripting API — the public
RCCstatic class. - 24 — Events System — events related to vehicle lifecycle.
- 16 — Input System — the normal player input pipeline.