Overview
Expert blueprint for racing games balancing physics, competition, and sense of speed.
When to Use
Use this skill when building any racing game genre including:
- Arcade racers (Need for Speed, Burnout style)
- Kart racing games (Mario Kart style)
- Realistic racing simulators (Assetto Corsa, Gran Turismo style)
- Time trial / ghost car systems
- Multiplayer competitive racing
- Any game requiring vehicle physics, checkpoint systems, AI opponents, drift mechanics, or racing UI
Core Loop
- Race: Player controls a vehicle on a track.
- Compete: Player overtakes opponents or beats the clock.
- Upgrade: Player earns currency/points to buy parts/cars.
- Tune: Player adjusts vehicle stats (grip, acceleration).
- Master: Player learns track layouts and optimal lines.
Skill Chain
| Phase |
Skills |
Purpose |
| 1. Physics |
physics-bodies, vehicle-wheel-3d |
Car movement, suspension, collisions |
| 2. AI |
navigation, steering-behaviors |
Opponent pathfinding, rubber-banding |
| 3. Input |
input-mapping |
Analog steering, acceleration, braking |
| 4. UI |
progress-bars, labels |
Speedometer, lap timer, minimap |
| 5. Feel |
camera-shake, godot-particles |
Speed perception, tire smoke, sparks |
Prerequisites
- Godot 4.x project with 3D setup.
- Input actions mapped:
right, left, forward, back (or equivalent analog axes).
- Basic understanding of
VehicleBody3D and VehicleWheel3D.
Procedure
1. Vehicle Controller Setup
- Create a
VehicleBody3D node.
- Attach
VehicleWheel3D nodes for each wheel.
- Load
scripts/arcade_vehicle_physics.gd when implementing high-performance arcade handling with custom gravity, air control, and friction-slip drifting.
- Load
scripts/raycast_suspension.gd when configuring spring/damper models for raycast wheels with configurable stiffness.
- Implement steering and engine force:
# car_controller.gd
extends VehicleBody3D
@export var max_torque: float = 300.0
@export var max_steering: float = 0.4
func _physics_process(delta: float) -> void:
steering = lerp(steering, Input.get_axis("right", "left") * max_steering, 5 * delta)
engine_force = Input.get_axis("back", "forward") * max_torque
2. Checkpoint System
- Place
Area3D nodes sequentially along the track.
- Load
scripts/lap_tracker.gd for high-precision lap management with sequential checkpoint logic.
- Load
scripts/racing_checkpoint.gd for indexed trigger gate modular track-based lap progression.
- Implement validation:
# checkpoint_manager.gd
extends Node
var checkpoints: Array[Area3D] = []
var current_checkpoint_index: int = 0
signal lap_completed
func _on_checkpoint_entered(body: Node3D, index: int) -> void:
if index == current_checkpoint_index + 1:
current_checkpoint_index = index
elif index == 0 and current_checkpoint_index == checkpoints.size() - 1:
complete_lap()
func complete_lap() -> void:
current_checkpoint_index = 0
lap_completed.emit()
3. Race Manager
- Create a high-level state machine for race states (COUNTDOWN, RACING, FINISHED).
- Use
await for async countdown timers.
# race_manager.gd
extends Node
enum State { COUNTDOWN, RACING, FINISHED }
var current_state: State = State.COUNTDOWN
var elapsed_time: float = 0.0
func start_race() -> void:
await countdown()
current_state = State.RACING
func _process(delta: float) -> void:
if current_state == State.RACING:
elapsed_time += delta
func countdown() -> void:
var count = 3
while count > 0:
await get_tree().create_timer(1.0).timeout
count -= 1
4. AI & Competition
- Load
scripts/spline_ai_controller.gd when implementing professional racing AI using Path3D predictive steering and rubber-banding logic.
- Load
scripts/slipstream_handler.gd when adding drafting zones with relative dot-product checks for speed boosts.
- Implement rubber-banding to keep races competitive:
class_name RubberBandingSystem extends Node
@export var player_vehicle: VehicleBody3D
@export var base_speed: float = 120.0
func update_ai_speed(ai_car: VehicleBody3D) -> void:
if not is_instance_valid(player_vehicle):
return
var dist = ai_car.global_position.distance_to(player_vehicle.global_position)
var ai_is_ahead = ai_car_is_ahead_of_player(ai_car, player_vehicle)
if ai_is_ahead:
ai_car.max_speed = base_speed * 0.9
else:
ai_car.max_speed = base_speed * 1.1
func ai_car_is_ahead_of_player(ai_car: VehicleBody3D, player: VehicleBody3D) -> bool:
var forward_dir = -player.global_transform.basis.z.normalized()
var to_ai = (ai_car.global_position - player.global_position).normalized()
return forward_dir.dot(to_ai) > 0.0
5. Drifting & Boost Mechanics
- Implement drift by reducing friction or applying sideways force.
- Load
scripts/arcade_vehicle_controller.gd for an alternative tight, raycast-based vehicle movement model for non-physics karts.
- Implement Drift-Boost (Mini-Turbo) by accumulating charge and applying
apply_central_impulse():
class_name DriftBoostSystem extends Node
@export var vehicle: VehicleBody3D
var drift_charge: float = 0.0
const BOOST_MULTIPLIER = 1000.0
var is_drifting: bool = false
func _physics_process(delta: float) -> void:
if not is_instance_valid(vehicle):
return
if is_drifting:
drift_charge += delta
elif drift_charge > 0.0:
execute_boost()
func execute_boost() -> void:
if is_instance_valid(vehicle):
var boost_force := -vehicle.global_transform.basis.z * (drift_charge * BOOST_MULTIPLIER)
vehicle.apply_central_impulse(boost_force)
drift_charge = 0.0
6. Visuals, Audio, & UI
- Load
scripts/skid_mark_emitter.gd when implementing conditional tire-slip trail systems for persistent visual feedback.
- Load
scripts/engine_audio_controller.gd for RPM-to-pitch audio synthesis for engine revving and gear shifts.
- Load
scripts/minimap_icon_projector.gd for 3D-to-2D bridge for projecting racers onto a localized UI.
- Load
scripts/force_feedback_router.gd for haptic and rumble management based on terrain and collisions.
- Load
scripts/ghost_recorder.gd for binary transform serialization for lightweight ghost car playback.
- Attach
GPUParticles3D to wheels for tire smoke, toggling emitting based on wheel.get_skidinfo() < 0.5.
- Use
SubViewport for rear-view mirror or minimap texture.
- Use
Doppler effect on AudioListener for realistic passing sounds.
Pitfalls
Physics & Handling
- NEVER use a rigid camera attachment; strictly use a Smooth Follow pattern with
lerp() to prevent motion sickness.
- NEVER prioritize realism over fun; strictly increase Gravity Scale (2x-3x) and keep friction high for responsive arcade feel.
- NEVER use
VehicleBody3D default settings for karts; strictly rewrite suspension using Raycasts or custom spring/damper models.
- NEVER apply steering torque directly to mass; strictly use a steering curve factored by lateral velocity.
- NEVER calculate suspension without a damper model; strictly include damping to prevent eternal oscillation (bouncing).
- NEVER ignore the Center of Mass property; strictly offset it downward to ensure stability during high-speed turns.
- NEVER multiply engine force by
delta; it is an integrated force in the physics solver.
- NEVER rely on
is_action_pressed() for manual gear shifting; strictly use is_action_just_pressed() for single-tap accuracy.
AI & Competition
- NEVER use static AI speeds; strictly use Rubber-Banding to keep races competitive based on player distance.
- NEVER run AI pathfinding across the entire track every frame; strictly use a "Look-Ahead" point on a spline/path.
- NEVER ignore racing Checkpoints; strictly enforce sequential
Area3D validation to prevent track shortcuts.
- NEVER use standard
Area3D for slipstreaming without a Dot Product check to ensure the player is directly behind.
Visuals & Audio
- NEVER skip "Sense of Speed" effects; strictly implement dynamic FOV scaling, motion blur, and high-speed camera shake.
- NEVER update minimap transforms for static elements in
_process(); strictly update dynamic racers only.
- NEVER serialize ghost cars as mass transform lists; strictly store positions/quaternions at fixed intervals.
- NEVER use constant pitch for engine sounds; strictly map RPM or engine load to
pitch_scale.
- NEVER spawn particles for skid marks every frame; strictly use Trail3D or procedural strips for low-cost persistence.
- NEVER use standard Strings for surface detection; strictly use
StringName (e.g., &"asphalt").
Security & Deprecation
- NEVER expose raw file paths when saving ghost data; always sanitize and use
FileAccess with the User directory to avoid path traversal.
- NEVER rely on the deprecated
yield() for async; use await with Callable or Signal as shown in the Race Manager.
- NEVER store sensitive player telemetry in plain text; encrypt or hash if transmitting over network.
Verification
Related skills
- godot-master - Master Godot skill reference
physics-bodies - RigidBody3D, VehicleBody3D physics fundamentals
vehicle-wheel-3d - Wheel configuration, suspension tuning
navigation - Path3D, NavigationServer for AI pathfinding
steering-behaviors - Seek, flee, arrival for AI movement
input-mapping - Analog input handling for steering/acceleration
progress-bars - Speedometer, fuel gauge, boost meter UI
labels - Lap timer, position counter, sector times
camera-shake - Impact, rumble, high-speed shake effects
godot-particles - Tire smoke, sparks, dust trails
1---2name: game-godot-genre-racing3description: Blueprints Godot 4 racing: VehicleBody3D and VehicleWheel3D, sequential checkpoints, rubber-banding AI, drift-boost, speed-FOV camera, lap UI, and ghost cars. Use when building arcade, kart, or sim racers, time trials, or track vehicle physics. Not for Godot MultiplayerAPI/RPC (networking-multiplayer) or non-racing vehicle sandboxes. Do not use for 2D platformers or other genre chairs.4---5
6## Overview
7Expert blueprint for racing games balancing physics, competition, and sense of speed.
8
9## When to Use
10Use this skill when building any racing game genre including:
11- Arcade racers (Need for Speed, Burnout style)
12- Kart racing games (Mario Kart style)
13- Realistic racing simulators (Assetto Corsa, Gran Turismo style)
14- Time trial / ghost car systems
15- Multiplayer competitive racing
16- Any game requiring vehicle physics, checkpoint systems, AI opponents, drift mechanics, or racing UI
17
18### Core Loop
191. **Race**: Player controls a vehicle on a track.
202. **Compete**: Player overtakes opponents or beats the clock.
213. **Upgrade**: Player earns currency/points to buy parts/cars.
224. **Tune**: Player adjusts vehicle stats (grip, acceleration).
235. **Master**: Player learns track layouts and optimal lines.
24
25### Skill Chain
26| Phase | Skills | Purpose |
27|-------|--------|---------|
28| 1. Physics | `physics-bodies`, `vehicle-wheel-3d` | Car movement, suspension, collisions |
29| 2. AI | `navigation`, `steering-behaviors` | Opponent pathfinding, rubber-banding |
30| 3. Input | `input-mapping` | Analog steering, acceleration, braking |
31| 4. UI | `progress-bars`, `labels` | Speedometer, lap timer, minimap |
32| 5. Feel | `camera-shake`, `godot-particles` | Speed perception, tire smoke, sparks |
33
34## Prerequisites
35- Godot 4.x project with 3D setup.
36- Input actions mapped: `right`, `left`, `forward`, `back` (or equivalent analog axes).
37- Basic understanding of `VehicleBody3D` and `VehicleWheel3D`.
38
39## Procedure
40
41### 1. Vehicle Controller Setup
421. Create a `VehicleBody3D` node.
432. Attach `VehicleWheel3D` nodes for each wheel.
443. Load `scripts/arcade_vehicle_physics.gd` when implementing high-performance arcade handling with custom gravity, air control, and friction-slip drifting.
454. Load `scripts/raycast_suspension.gd` when configuring spring/damper models for raycast wheels with configurable stiffness.
465. Implement steering and engine force:
47```gdscript
48# car_controller.gd
49extends VehicleBody3D
50
51@export var max_torque: float = 300.0
52@export var max_steering: float = 0.4
53
54func _physics_process(delta: float) -> void:
55 steering = lerp(steering, Input.get_axis("right", "left") * max_steering, 5 * delta)
56 engine_force = Input.get_axis("back", "forward") * max_torque
57```
58
59### 2. Checkpoint System
601. Place `Area3D` nodes sequentially along the track.
612. Load `scripts/lap_tracker.gd` for high-precision lap management with sequential checkpoint logic.
623. Load `scripts/racing_checkpoint.gd` for indexed trigger gate modular track-based lap progression.
634. Implement validation:
64```gdscript
65# checkpoint_manager.gd
66extends Node
67
68var checkpoints: Array[Area3D] = []
69var current_checkpoint_index: int = 0
70signal lap_completed
71
72func _on_checkpoint_entered(body: Node3D, index: int) -> void:
73 if index == current_checkpoint_index + 1:
74 current_checkpoint_index = index
75 elif index == 0 and current_checkpoint_index == checkpoints.size() - 1:
76 complete_lap()
77
78func complete_lap() -> void:
79 current_checkpoint_index = 0
80 lap_completed.emit()
81```
82
83### 3. Race Manager
841. Create a high-level state machine for race states (COUNTDOWN, RACING, FINISHED).
852. Use `await` for async countdown timers.
86```gdscript
87# race_manager.gd
88extends Node
89
90enum State { COUNTDOWN, RACING, FINISHED }
91var current_state: State = State.COUNTDOWN
92var elapsed_time: float = 0.0
93
94func start_race() -> void:
95 await countdown()
96 current_state = State.RACING
97
98func _process(delta: float) -> void:
99 if current_state == State.RACING:
100 elapsed_time += delta
101
102func countdown() -> void:
103 var count = 3
104 while count > 0:
105 await get_tree().create_timer(1.0).timeout
106 count -= 1
107```
108
109### 4. AI & Competition
1101. Load `scripts/spline_ai_controller.gd` when implementing professional racing AI using Path3D predictive steering and rubber-banding logic.
1112. Load `scripts/slipstream_handler.gd` when adding drafting zones with relative dot-product checks for speed boosts.
1123. Implement rubber-banding to keep races competitive:
113```gdscript
114class_name RubberBandingSystem extends Node
115
116@export var player_vehicle: VehicleBody3D
117@export var base_speed: float = 120.0
118
119func update_ai_speed(ai_car: VehicleBody3D) -> void:
120 if not is_instance_valid(player_vehicle):
121 return
122
123 var dist = ai_car.global_position.distance_to(player_vehicle.global_position)
124 var ai_is_ahead = ai_car_is_ahead_of_player(ai_car, player_vehicle)
125
126 if ai_is_ahead:
127 ai_car.max_speed = base_speed * 0.9
128 else:
129 ai_car.max_speed = base_speed * 1.1
130
131func ai_car_is_ahead_of_player(ai_car: VehicleBody3D, player: VehicleBody3D) -> bool:
132 var forward_dir = -player.global_transform.basis.z.normalized()
133 var to_ai = (ai_car.global_position - player.global_position).normalized()
134 return forward_dir.dot(to_ai) > 0.0
135```
136
137### 5. Drifting & Boost Mechanics
1381. Implement drift by reducing friction or applying sideways force.
1392. Load `scripts/arcade_vehicle_controller.gd` for an alternative tight, raycast-based vehicle movement model for non-physics karts.
1403. Implement Drift-Boost (Mini-Turbo) by accumulating charge and applying `apply_central_impulse()`:
141```gdscript
142class_name DriftBoostSystem extends Node
143
144@export var vehicle: VehicleBody3D
145var drift_charge: float = 0.0
146const BOOST_MULTIPLIER = 1000.0
147var is_drifting: bool = false
148
149func _physics_process(delta: float) -> void:
150 if not is_instance_valid(vehicle):
151 return
152
153 if is_drifting:
154 drift_charge += delta
155 elif drift_charge > 0.0:
156 execute_boost()
157
158func execute_boost() -> void:
159 if is_instance_valid(vehicle):
160 var boost_force := -vehicle.global_transform.basis.z * (drift_charge * BOOST_MULTIPLIER)
161 vehicle.apply_central_impulse(boost_force)
162 drift_charge = 0.0
163```
164
165### 6. Visuals, Audio, & UI
1661. Load `scripts/skid_mark_emitter.gd` when implementing conditional tire-slip trail systems for persistent visual feedback.
1672. Load `scripts/engine_audio_controller.gd` for RPM-to-pitch audio synthesis for engine revving and gear shifts.
1683. Load `scripts/minimap_icon_projector.gd` for 3D-to-2D bridge for projecting racers onto a localized UI.
1694. Load `scripts/force_feedback_router.gd` for haptic and rumble management based on terrain and collisions.
1705. Load `scripts/ghost_recorder.gd` for binary transform serialization for lightweight ghost car playback.
1716. Attach `GPUParticles3D` to wheels for tire smoke, toggling `emitting` based on `wheel.get_skidinfo() < 0.5`.
1727. Use `SubViewport` for rear-view mirror or minimap texture.
1738. Use `Doppler` effect on `AudioListener` for realistic passing sounds.
174
175## Pitfalls
176
177### Physics & Handling
178- NEVER use a rigid camera attachment; strictly use a **Smooth Follow** pattern with `lerp()` to prevent motion sickness.
179- NEVER prioritize realism over fun; strictly increase **Gravity Scale** (2x-3x) and keep friction high for responsive arcade feel.
180- NEVER use `VehicleBody3D` default settings for karts; strictly rewrite suspension using Raycasts or custom spring/damper models.
181- NEVER apply steering torque directly to mass; strictly use a steering curve factored by lateral velocity.
182- NEVER calculate suspension without a damper model; strictly include damping to prevent eternal oscillation (bouncing).
183- NEVER ignore the **Center of Mass** property; strictly offset it downward to ensure stability during high-speed turns.
184- NEVER multiply engine force by `delta`; it is an integrated force in the physics solver.
185- NEVER rely on `is_action_pressed()` for manual gear shifting; strictly use `is_action_just_pressed()` for single-tap accuracy.
186
187### AI & Competition
188- NEVER use static AI speeds; strictly use **Rubber-Banding** to keep races competitive based on player distance.
189- NEVER run AI pathfinding across the entire track every frame; strictly use a "Look-Ahead" point on a spline/path.
190- NEVER ignore racing **Checkpoints**; strictly enforce sequential `Area3D` validation to prevent track shortcuts.
191- NEVER use standard `Area3D` for slipstreaming without a **Dot Product** check to ensure the player is directly behind.
192
193### Visuals & Audio
194- NEVER skip "Sense of Speed" effects; strictly implement dynamic **FOV scaling**, motion blur, and high-speed camera shake.
195- NEVER update minimap transforms for static elements in `_process()`; strictly update dynamic racers only.
196- NEVER serialize ghost cars as mass transform lists; strictly store positions/quaternions at fixed intervals.
197- NEVER use constant pitch for engine sounds; strictly map RPM or engine load to `pitch_scale`.
198- NEVER spawn particles for skid marks every frame; strictly use **Trail3D** or procedural strips for low-cost persistence.
199- NEVER use standard Strings for surface detection; strictly use `StringName` (e.g., `&"asphalt"`).
200
201### Security & Deprecation
202- NEVER expose raw file paths when saving ghost data; always sanitize and use `FileAccess` with the `User` directory to avoid path traversal.
203- NEVER rely on the deprecated `yield()` for async; use `await` with `Callable` or `Signal` as shown in the Race Manager.
204- NEVER store sensitive player telemetry in plain text; encrypt or hash if transmitting over network.
205
206## Verification
207- [ ] Verify VehicleBody3D center of mass is offset downward for stability
208- [ ] Confirm gravity scale is set to 2.0-3.0 for arcade feel
209- [ ] Test checkpoint system prevents shortcuts (sequential validation)
210- [ ] Verify rubber-banding AI adjusts speed based on player distance
211- [ ] Confirm drift mechanic reduces lateral friction and provides exit boost
212- [ ] Test camera uses smooth follow (lerp) not rigid attachment
213- [ ] Verify FOV scales with speed for sense of speed
214- [ ] Confirm engine audio pitch maps to RPM/engine load
215- [ ] Test ghost recorder uses binary serialization (PackedVector3Array)
216- [ ] Verify skid marks use Trail3D not per-frame particles
217- [ ] Confirm minimap only updates dynamic elements in _process()
218- [ ] Test slipstream uses dot product for behind-check
219- [ ] Verify suspension includes damper model (no eternal oscillation)
220- [ ] Confirm steering uses curve factored by lateral velocity
221- [ ] Test gear shifting uses is_action_just_pressed() not is_action_pressed()
222- [ ] Ensure no deprecated `yield()` calls remain in scripts
223- [ ] Validate all file I/O uses sanitized paths within `user://` directory
224
225## Related skills
226- [godot-master](../godot-master/SKILL.md) - Master Godot skill reference
227- `physics-bodies` - RigidBody3D, VehicleBody3D physics fundamentals
228- `vehicle-wheel-3d` - Wheel configuration, suspension tuning
229- `navigation` - Path3D, NavigationServer for AI pathfinding
230- `steering-behaviors` - Seek, flee, arrival for AI movement
231- `input-mapping` - Analog input handling for steering/acceleration
232- `progress-bars` - Speedometer, fuel gauge, boost meter UI
233- `labels` - Lap timer, position counter, sector times
234- `camera-shake` - Impact, rumble, high-speed shake effects
235- `godot-particles` - Tire smoke, sparks, dust trails