Modes: Cruise / Crash Mode (60s damage dollars) / Race (3 laps, rubber-banded rivals). Burnout loop: boost earned by drift, near miss, smash; takedowns refill and grow the meter to 4x; hard crashes shed det_* panels and trigger Impact Time slow-mo. Traffic follows the level RacePath frozen-kinematic and goes dynamic when whacked. tools/build_cars.py builds six Aussie shitbox GLBs (profile extrusion + detachable doors/mirrors/bumpers/bonnet/boot). Smoke test covers all three modes headless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
55 lines
2.0 KiB
GDScript
55 lines
2.0 KiB
GDScript
extends Node3D
|
|
## ponytail: placeholder carpark built in code -- real levels arrive as level.glb from Blender
|
|
## and this whole folder becomes just the GLB + nothing else.
|
|
|
|
func _ready() -> void:
|
|
var rng := RandomNumberGenerator.new()
|
|
rng.seed = 8
|
|
_box(Vector3(0, -0.5, 0), Vector3(240, 1, 160), Color(0.35, 0.35, 0.37)) # tarmac
|
|
for side in [-1, 1]: # kerb walls
|
|
_box(Vector3(0, 0.4, side * 79.0), Vector3(240, 0.8, 2), Color(0.6, 0.6, 0.6))
|
|
_box(Vector3(side * 119.0, 0.4, 0), Vector3(2, 0.8, 160), Color(0.6, 0.6, 0.6))
|
|
for row in 4: # rows of parked shitboxes, shuntable
|
|
for bay in 10:
|
|
if rng.randf() < 0.35:
|
|
continue
|
|
var pos := Vector3(-27.0 + bay * 6.0, 0.8, -30.0 + row * 18.0)
|
|
_box(pos, Vector3(1.9, 1.4, 4.4), Color.from_hsv(rng.randf(), 0.5, rng.randf_range(0.4, 0.9)), true)
|
|
for i in 6: # light poles
|
|
_box(Vector3(-30.0 + i * 12.0, 3.0, 8.0), Vector3(0.4, 6.0, 0.4), Color(0.3, 0.3, 0.3))
|
|
_race_path()
|
|
|
|
func _race_path() -> void:
|
|
# perimeter loop road around the parking rows -- race line + traffic route
|
|
var path := Path3D.new()
|
|
path.name = "RacePath"
|
|
var c := Curve3D.new()
|
|
var pts := [Vector3(45, 0, 55), Vector3(45, 0, -55), Vector3(-45, 0, -55), Vector3(-45, 0, 55)]
|
|
for i in pts.size() + 1:
|
|
var p: Vector3 = pts[i % pts.size()]
|
|
var to_prev: Vector3 = (pts[(i - 1 + pts.size()) % pts.size()] - p).normalized() * 12.0
|
|
var to_next: Vector3 = (pts[(i + 1) % pts.size()] - p).normalized() * 12.0
|
|
c.add_point(p, to_prev, to_next)
|
|
path.curve = c
|
|
add_child(path)
|
|
|
|
func _box(pos: Vector3, size: Vector3, color: Color, dynamic := false) -> void:
|
|
var body: PhysicsBody3D = RigidBody3D.new() if dynamic else StaticBody3D.new()
|
|
if dynamic:
|
|
body.mass = 300.0
|
|
var shape := CollisionShape3D.new()
|
|
var bs := BoxShape3D.new()
|
|
bs.size = size
|
|
shape.shape = bs
|
|
var mi := MeshInstance3D.new()
|
|
var bm := BoxMesh.new()
|
|
bm.size = size
|
|
var mat := StandardMaterial3D.new()
|
|
mat.albedo_color = color
|
|
bm.material = mat
|
|
mi.mesh = bm
|
|
body.add_child(shape)
|
|
body.add_child(mi)
|
|
body.position = pos
|
|
add_child(body)
|