small racing game im working on
splitscreen foundations
bendn 2023-02-16
parent f54cbea · commit 70b4b8b
-rw-r--r--.gitignore3
-rw-r--r--assets/cars/kenney_sedan/sedan.blendbin1143224 -> 1142840 bytes
-rw-r--r--assets/cars/kenney_sedan/sedan.blend.import2
-rw-r--r--assets/cars/kenney_sedan/sedan.tscn2
-rw-r--r--assets/textures/base-noise.png.import7
-rw-r--r--assets/textures/grass.png.import7
-rw-r--r--cam.gd20
-rw-r--r--classes/car.gd14
-rw-r--r--classes/timer.gd26
-rw-r--r--classes/trackdata.gd4
-rw-r--r--globals.gd3
-rw-r--r--godot.lock5
-rw-r--r--godot.package1
-rw-r--r--project.godot9
-rw-r--r--race.gd106
-rw-r--r--race.tscn269
-rw-r--r--scenes/floor.tscn19
-rw-r--r--scenes/race_high.tscn21
-rw-r--r--scenes/race_highlevel.gd29
-rw-r--r--scenes/track-base.gd4
-rw-r--r--start.tscn39
-rw-r--r--tracks/multilap_test.tres2
-rw-r--r--tracks/test.tres2
-rw-r--r--ui/countdown.tscn97
-rw-r--r--ui/hud.gd8
-rw-r--r--ui/hud.tscn111
-rw-r--r--ui/intro_cam.gd29
-rw-r--r--ui/laps.gd12
-rw-r--r--ui/map.gd14
-rw-r--r--ui/speedometer.gd6
-rw-r--r--ui/splits/splits.gd1
-rw-r--r--ui/timer.gd25
-rw-r--r--ui/tracks.gd17
33 files changed, 509 insertions, 405 deletions
diff --git a/.gitignore b/.gitignore
index d59960c..4fd41e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,6 @@
movie.*
*.blend1
addons/
+*.x86_64
+godot.lock
+export_presets.cfg
diff --git a/assets/cars/kenney_sedan/sedan.blend b/assets/cars/kenney_sedan/sedan.blend
index 5b1d311..755ede5 100644
--- a/assets/cars/kenney_sedan/sedan.blend
+++ b/assets/cars/kenney_sedan/sedan.blend
Binary files differ
diff --git a/assets/cars/kenney_sedan/sedan.blend.import b/assets/cars/kenney_sedan/sedan.blend.import
index cc6db4d..485d322 100644
--- a/assets/cars/kenney_sedan/sedan.blend.import
+++ b/assets/cars/kenney_sedan/sedan.blend.import
@@ -26,8 +26,10 @@ skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
+animation/remove_immutable_tracks=true
import_script/path=""
_subresources={}
+gltf/embedded_image_handling=1
blender/nodes/visible=0
blender/nodes/punctual_lights=true
blender/nodes/cameras=true
diff --git a/assets/cars/kenney_sedan/sedan.tscn b/assets/cars/kenney_sedan/sedan.tscn
index 8ac24bf..fd2d275 100644
--- a/assets/cars/kenney_sedan/sedan.tscn
+++ b/assets/cars/kenney_sedan/sedan.tscn
@@ -17,6 +17,7 @@ albedo_color = Color(0.239216, 0.239216, 0.239216, 1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_gjgu8"]
resource_name = "paintRed"
+transparency = 1
vertex_color_use_as_albedo = true
albedo_color = Color(1, 0.227451, 0.360134, 1)
metallic = 1.0
@@ -342,6 +343,7 @@ collision_layer = 2
collision_mask = 3
mass = 3.0
physics_material_override = SubResource("PhysicsMaterial_grep7")
+freeze = true
[node name="Coll" type="CollisionShape3D" parent="Ball"]
shape = SubResource("SphereShape3D_2sf22")
diff --git a/assets/textures/base-noise.png.import b/assets/textures/base-noise.png.import
index f949462..7431d5e 100644
--- a/assets/textures/base-noise.png.import
+++ b/assets/textures/base-noise.png.import
@@ -4,23 +4,22 @@ importer="texture"
type="CompressedTexture2D"
uid="uid://11wgfnak257h"
path.s3tc="res://.godot/imported/base-noise.png-1465006bf87670e88934396a47068ff4.s3tc.ctex"
-path.etc2="res://.godot/imported/base-noise.png-1465006bf87670e88934396a47068ff4.etc2.ctex"
metadata={
-"imported_formats": ["s3tc", "etc2"],
+"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://assets/textures/base-noise.png"
-dest_files=["res://.godot/imported/base-noise.png-1465006bf87670e88934396a47068ff4.s3tc.ctex", "res://.godot/imported/base-noise.png-1465006bf87670e88934396a47068ff4.etc2.ctex"]
+dest_files=["res://.godot/imported/base-noise.png-1465006bf87670e88934396a47068ff4.s3tc.ctex"]
[params]
compress/mode=2
+compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
-compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
diff --git a/assets/textures/grass.png.import b/assets/textures/grass.png.import
index 8b746fe..df819ed 100644
--- a/assets/textures/grass.png.import
+++ b/assets/textures/grass.png.import
@@ -4,23 +4,22 @@ importer="texture"
type="CompressedTexture2D"
uid="uid://dyk71hogwv01g"
path.s3tc="res://.godot/imported/grass.png-44de1b601ed5e0482c9aa195977ab90c.s3tc.ctex"
-path.etc2="res://.godot/imported/grass.png-44de1b601ed5e0482c9aa195977ab90c.etc2.ctex"
metadata={
-"imported_formats": ["s3tc", "etc2"],
+"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://assets/textures/grass.png"
-dest_files=["res://.godot/imported/grass.png-44de1b601ed5e0482c9aa195977ab90c.s3tc.ctex", "res://.godot/imported/grass.png-44de1b601ed5e0482c9aa195977ab90c.etc2.ctex"]
+dest_files=["res://.godot/imported/grass.png-44de1b601ed5e0482c9aa195977ab90c.s3tc.ctex"]
[params]
compress/mode=2
+compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
-compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
diff --git a/cam.gd b/cam.gd
index 88ffdb9..f3e5625 100644
--- a/cam.gd
+++ b/cam.gd
@@ -1,14 +1,16 @@
extends Camera3D
+class_name CarCamera
-var follow_this: Node3D
-@export var target_distance = 3.0
-@export var target_height = 2.0
+@export var target_distance = 9.0
+@export var target_height = 4.0
-var last_lookat
+var follow_this: Node3D
+var last_lookat: Vector3
func _ready():
- set_physics_process(false)
-
+ global_position = follow_this.global_position + (follow_this.global_transform.basis.z * target_distance)
+ look_at(follow_this.global_position)
+ last_lookat = follow_this.global_position
func target() -> Vector3:
var delta_v := global_position - follow_this.global_position
@@ -32,9 +34,5 @@ func _physics_process(delta):
look_at(last_lookat, Vector3(0.0, 1.0, 0.0))
-func _on_race_created_car(car: Car) -> void:
+func _init(car: Car) -> void:
follow_this = car.car_mesh
- global_position = follow_this.global_position + (follow_this.global_transform.basis.z * target_distance)
- look_at(follow_this.global_position)
- last_lookat = follow_this.global_position
- set_physics_process(true)
diff --git a/classes/car.gd b/classes/car.gd
index 0786a0f..5ecd629 100644
--- a/classes/car.gd
+++ b/classes/car.gd
@@ -28,6 +28,7 @@ var _steering := 0.0
func _ready():
$Ball/DebugMesh.visible = show_debug
ground_ray.add_exception(ball)
+ set_physics_process(false)
func steer(to: float) -> void:
_steering = clamp(lerpf(_steering, -to, wheel_turn_speed), -max_steering_range, max_steering_range)
@@ -66,9 +67,9 @@ func kph() -> float:
func spin_kph() -> float:
return (ball.angular_velocity.length_squared() / 12)
-func limit() -> void:
- ball.linear_damp = max(.1 * (kph() - limit_speed), 0) if kph() > limit_speed else 0.0
- ball.angular_damp = max(.1 * (spin_kph() - limit_spin), 0) if spin_kph() > limit_spin else 0.0
+func limit(delta: float) -> void:
+ ball.linear_damp = max((.5 * delta) * (kph() - limit_speed), 0) if kph() > limit_speed else 0.0
+ ball.angular_damp = max(5 * (spin_kph() - limit_spin), 0) if spin_kph() > limit_spin else 0.0
func _physics_process(delta: float) -> void:
move_mesh(delta)
@@ -85,8 +86,7 @@ func _physics_process(delta: float) -> void:
skid_l.emitting = drift
skid_r.emitting = drift
- limit()
-
+ limit(delta)
turn(delta)
floor_mesh(delta)
@@ -95,3 +95,7 @@ func align_with_y(xform: Transform3D, new_y: Vector3) -> Transform3D:
xform.basis.x = -xform.basis.z.cross(new_y)
xform.basis = xform.basis.orthonormalized()
return xform
+
+func start() -> void:
+ ball.freeze = false
+ set_physics_process(true)
diff --git a/classes/timer.gd b/classes/timer.gd
new file mode 100644
index 0000000..01684b5
--- /dev/null
+++ b/classes/timer.gd
@@ -0,0 +1,26 @@
+extends Node
+class_name GameTimer
+
+var elapsed_time: float = 0.0
+
+func _ready() -> void:
+ stop()
+
+func start() -> void:
+ set_process(true)
+
+func stop() -> void:
+ set_process(false)
+
+func now() -> float:
+ return elapsed_time
+
+## format a number of seconds into m:s.ms
+static func format(time: float) -> String:
+ return "%01d:%02d.%02d" % [time / 60, fmod(time, 60), fmod(time * 1000, 100)]
+
+func fmt_now() -> String:
+ return GameTimer.format(elapsed_time)
+
+func _process(delta: float) -> void:
+ elapsed_time += delta \ No newline at end of file
diff --git a/classes/trackdata.gd b/classes/trackdata.gd
index 3ac8175..225a385 100644
--- a/classes/trackdata.gd
+++ b/classes/trackdata.gd
@@ -4,7 +4,7 @@ extends Resource
const SaveLoad := preload("res://addons/@bendn/remap/private/SaveLoadUtils.gd")
var time: float
-var checkpoints: Array[PackedFloat32Array]
+var checkpoints: Array#[PackedFloat32Array]
var positional := {
origins = PackedVector3Array(),
rotations = PackedVector3Array(),
@@ -17,7 +17,7 @@ func data() -> Dictionary:
func _init(num_checkpoints := 0, laps := 0) -> void:
for i in laps:
- var arr: PackedFloat32Array = []
+ var arr := []
arr.resize(num_checkpoints + 1)
arr.fill(-1)
checkpoints.append(arr)
diff --git a/globals.gd b/globals.gd
new file mode 100644
index 0000000..7cb7939
--- /dev/null
+++ b/globals.gd
@@ -0,0 +1,3 @@
+extends Node
+
+var playing: TrackResource
diff --git a/godot.lock b/godot.lock
index dbc3f12..0b8b91e 100644
--- a/godot.lock
+++ b/godot.lock
@@ -3,5 +3,10 @@
"name": "@bendn/remap",
"version": "5.0.6",
"integrity": "sha512-lfB0Vx/fmXhnrTttiG+sr33EFAlAEopDq9lX2bn3z+pp3dzSuMtTaRwbkUN8ndbuwfPa8Dm+NghUX2s3wHQFLQ=="
+ },
+ {
+ "name": "@bendn/splitter",
+ "version": "1.0.3",
+ "integrity": "sha512-A9z9qjP1Zvz3RnRuyRUrCK96ocAFDq3If/Gx+a/GgiGm3RhLIq0O0UWwWihSHEWcQlgZ9yUpLTPosfXEER3mhA=="
}
] \ No newline at end of file
diff --git a/godot.package b/godot.package
index c9a13a2..2e6c546 100644
--- a/godot.package
+++ b/godot.package
@@ -1,2 +1,3 @@
[packages]
"@bendn/remap" = '5.0.6'
+"@bendn/splitter" = '1.0.3'
diff --git a/project.godot b/project.godot
index db3c969..8bc881f 100644
--- a/project.godot
+++ b/project.godot
@@ -11,17 +11,20 @@ config_version=5
[application]
config/name="tracer"
-run/main_scene="res://race.tscn"
+run/main_scene="res://start.tscn"
config/use_custom_user_dir=true
config/custom_user_dir_name="tracer"
config/features=PackedStringArray("4.0")
+[autoload]
+
+Globals="*res://globals.gd"
+
[display]
window/size/viewport_width=1920
window/size/viewport_height=1080
-window/stretch/mode="viewport"
-window/stretch/aspect="expand"
+window/stretch/aspect="ignore"
[editor]
diff --git a/race.gd b/race.gd
index c8dcafb..d0af4dd 100644
--- a/race.gd
+++ b/race.gd
@@ -1,17 +1,22 @@
extends Node3D
+class_name Race
@export var car_scene: PackedScene
@export var ghost_scene: PackedScene
-@export var track: TrackLoader
-@export var splits: Control
-@export var timer: Control
-@onready var data := TrackSaveableData.new(track.checkpoints.size(), track.track.laps)
-@onready var best_time_data := TrackSaveableData._load(saves % track.track.name)
+@export var track_loader_scene: PackedScene
+
+# in order of initialization
+var track_res: TrackResource
+var track: TrackLoader
+var data: TrackSaveableData
+var best_time_data: TrackSaveableData
var car: Car
var ghost: GhostCar
-var current_lap := 0
var start_frame: int
+
+var current_lap := 0
var playing := false
+var timer := GameTimer.new()
const SaveLoad := preload("res://addons/@bendn/remap/private/SaveLoadUtils.gd")
const saves := "user://%s.trackdata"
@@ -20,6 +25,10 @@ signal next_lap
signal created_car(car: Car)
signal created_ghost(ghost: GhostCar)
signal finished
+signal split(time: float, prev_time: float)
+
+func initialize(t: TrackResource) -> void:
+ track_res = t
func mkghost() -> void:
var g: Node3D = ghost_scene.instantiate()
@@ -28,48 +37,57 @@ func mkghost() -> void:
add_child(ghost)
ghost.global_position = best_time_data.loadshot(0)[0]
ghost.global_rotation = best_time_data.loadshot(0)[1]
+ ghost.hide()
created_ghost.emit(ghost)
-func _ready() -> void:
- set_physics_process(false)
- if best_time_data:
- mkghost()
+func mkcar() -> void:
car = HumanCar.attach(car_scene)
- add_child(car)
- car.ball.freeze = true
car.visible = false
- car.global_position = track.start_pos + Vector3.UP * 3.5
- car.set_deferred(&"rotation", track.start_rot + Vector3.UP * PI)
- await get_tree().process_frame
- car.global_position = car.global_position - (car.ball.global_transform.basis.z * 2) # bump forward a teensy bit
+ add_child(car)
+ car.rotation = track.start_rot + Vector3(0, PI, -PI/2)
+ # car.set_deferred(&"rotation", track.start_rot + Vector3(0, PI, -PI/2))
+ car.global_position = track.start_pos + Vector3(0, 2, 0) - (car.ball.global_transform.basis.z * 2) # bump forward a teensy bit
car.visible = true
created_car.emit(car)
print("car created")
+
+func _ready() -> void:
+ set_physics_process(false)
+ track = track_loader_scene.instantiate()
+ track.track = track_res
+ add_child(track)
+ data = TrackSaveableData.new(track_res.checkpoints.size(), track_res.laps)
+ best_time_data = TrackSaveableData._load(saves % track_res.name)
+ mkcar()
+ if best_time_data:
+ mkghost()
+ connect_checkpoints()
+ add_child(timer)
+
+func connect_checkpoints() -> void:
for i in len(track.checkpoints):
- track.checkpoints[i].collected.connect(
- (func passed_cp(cp: int) -> void: if playing and data.checkpoints[current_lap][i] < 0: collect(cp))
- .bind(i))
-
- track.finish.collected.connect(
- func passed_finish() -> void:
- if !playing: return
- for i in len(data.checkpoints[current_lap]) - 1: # no any() function on packedfloat32
- if data.checkpoints[current_lap][i] < 0:
- return
- collect(-1)
- if track.track.laps - 1 == current_lap:
- finished.emit()
- playing = false
- print("finished")
- if not best_time_data or data.time < best_time_data.time:
- print("new pb!")
- SaveLoad.save(saves % track.track.name, data.data())
- # best_time_data = data # this messes with the ghost, and doesnt matter yet anyways (until i can reset)
- data = TrackSaveableData.new(track.checkpoints.size())
- else:
- current_lap += 1
- next_lap.emit()
- )
+ track.checkpoints[i].collected.connect(passed_cp.bind(i))
+ track.finish.collected.connect(passed_finish)
+
+func passed_cp(cp: int) -> void: if playing and data.checkpoints[current_lap][cp] < 0: collect(cp)
+
+func passed_finish() -> void:
+ if !playing: return
+ for i in len(data.checkpoints[current_lap]) - 1:
+ if data.checkpoints[current_lap][i] < 0:
+ return
+ collect(-1)
+ if track_res.laps - 1 == current_lap:
+ finished.emit()
+ playing = false
+ print("finished")
+ if not best_time_data or data.time < best_time_data.time:
+ print("new pb!")
+ SaveLoad.save(saves % track_res.name, data.data())
+ data = TrackSaveableData.new(track.checkpoints.size())
+ else:
+ current_lap += 1
+ next_lap.emit()
func _physics_process(_delta: float) -> void:
data.snapshot(car)
@@ -86,12 +104,14 @@ func _physics_process(_delta: float) -> void:
func collect(cp: int) -> void:
var time := best_time_data.get_time(current_lap, cp) if best_time_data else -1.0
- time = best_time_data.time if (not track.track.laps or track.track.laps == current_lap + 1) and cp == -1 and time != -1.0 else time
- splits.update(timer.now(), time)
+ time = best_time_data.time if (not track_res.laps or track_res.laps == current_lap + 1) and cp == -1 and time != -1.0 else time
+ split.emit(timer.now(), time)
data.collect(current_lap, cp, timer.now())
-func _on_intro_camera_race_started() -> void:
+func start() -> void:
+ timer.start()
start_frame = Engine.get_physics_frames()
playing = true
+ car.start()
set_physics_process(true)
diff --git a/race.tscn b/race.tscn
index ed914a0..cc6034e 100644
--- a/race.tscn
+++ b/race.tscn
@@ -1,280 +1,21 @@
-[gd_scene load_steps=28 format=3 uid="uid://cech6c4yrmcvq"]
+[gd_scene load_steps=8 format=3 uid="uid://cech6c4yrmcvq"]
[ext_resource type="Script" path="res://race.gd" id="1_ckbwd"]
[ext_resource type="Environment" uid="uid://biwshm46yl62v" path="res://default_env.tres" id="2_pnp7e"]
[ext_resource type="PackedScene" uid="uid://bbj2agqv581cd" path="res://assets/cars/kenney_sedan/sedan.blend" id="3_cb3p0"]
[ext_resource type="CameraAttributesPractical" uid="uid://nhsovwj5hjip" path="res://cam.tres" id="3_jx550"]
-[ext_resource type="Material" uid="uid://bdyn312e6c3ll" path="res://assets/mats/grass.tres" id="4_i1mlf"]
-[ext_resource type="Script" path="res://cam.gd" id="5_nb035"]
-[ext_resource type="Curve3D" uid="uid://u2f56xx8h2re" path="res://tracks/multilap_test_curve.tres" id="5_yk721"]
-[ext_resource type="Resource" uid="uid://crye0ijvmtsyb" path="res://tracks/multilap_test.tres" id="6_506fu"]
[ext_resource type="PackedScene" uid="uid://ccn1nk1a0b0sa" path="res://assets/cars/kenney_sedan/sedan.tscn" id="6_nu32e"]
-[ext_resource type="Theme" uid="uid://ch2uo5qd8ubx6" path="res://ui/theme.tres" id="7_6itw5"]
-[ext_resource type="Script" path="res://ui/speedometer.gd" id="8_awr5n"]
-[ext_resource type="Script" path="res://ui/timer.gd" id="9_dn61b"]
-[ext_resource type="Script" path="res://ui/map.gd" id="10_58kgt"]
+[ext_resource type="PackedScene" uid="uid://cd4a5y0hi58ks" path="res://scenes/floor.tscn" id="10_p60d8"]
[ext_resource type="PackedScene" uid="uid://clw61td2wh84w" path="res://scenes/track.tscn" id="11_6q53c"]
-[ext_resource type="PackedScene" uid="uid://nkh2xi7tnumc" path="res://ui/splits/splits.tscn" id="14_ge1w6"]
-[ext_resource type="Texture2D" uid="uid://bfe4ytl0vjosb" path="res://ui/assets/line.png" id="14_n0r0n"]
-[ext_resource type="Script" path="res://ui/intro_cam.gd" id="14_yajvg"]
-[ext_resource type="Script" path="res://ui/laps.gd" id="16_mxur4"]
-[ext_resource type="Texture2D" uid="uid://b3nmp7eyu0hjk" path="res://ui/assets/flag.png" id="16_rp311"]
-[ext_resource type="Texture2D" uid="uid://b6ad1yrgtg6qk" path="res://ui/assets/player_indicator.png" id="17_ptq57"]
-[ext_resource type="Texture2D" uid="uid://dkbrx7rpa8dvc" path="res://ui/assets/ghost.png" id="18_v7a53"]
-[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_tkhh8"]
-
-[sub_resource type="PlaneMesh" id="PlaneMesh_ta0cd"]
-material = ExtResource("4_i1mlf")
-size = Vector2(5000, 5000)
-
-[sub_resource type="Gradient" id="Gradient_2kvil"]
-offsets = PackedFloat32Array(0, 0.178744, 0.454106, 0.719807, 1)
-colors = PackedColorArray(0.85098, 0.85098, 0.85098, 1, 0.942823, 0.942823, 0.942822, 1, 0.868985, 0.868985, 0.868985, 1, 0.838897, 0.838897, 0.838897, 1, 0.85098, 0.85098, 0.85098, 1)
-
-[sub_resource type="Animation" id="Animation_2si4r"]
-length = 0.001
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Counter:text")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 1,
-"values": ["
-"]
-}
-
-[sub_resource type="Animation" id="Animation_uaks0"]
-resource_name = "count_in"
-length = 3.0
-step = 0.5
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Counter:text")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0, 1, 2, 3),
-"transitions": PackedFloat32Array(1, 1, 1, 1),
-"update": 1,
-"values": ["[center][b]3[/b][/center]", "[center][b]2[/b][/center]
-", "[center][b]1[/b][/center]
-", ""]
-}
-tracks/1/type = "value"
-tracks/1/imported = false
-tracks/1/enabled = true
-tracks/1/path = NodePath("Counter:theme_override_colors/default_color")
-tracks/1/interp = 1
-tracks/1/loop_wrap = true
-tracks/1/keys = {
-"times": PackedFloat32Array(0, 3),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Color(1, 0.360784, 0.227451, 1), Color(0.980392, 0.737255, 0, 1)]
-}
-tracks/2/type = "method"
-tracks/2/imported = false
-tracks/2/enabled = true
-tracks/2/path = NodePath("CanvasLayer/HBoxContainer/Panel2/Timer")
-tracks/2/interp = 1
-tracks/2/loop_wrap = true
-tracks/2/keys = {
-"times": PackedFloat32Array(3),
-"transitions": PackedFloat32Array(1),
-"values": [{
-"args": [],
-"method": &"start"
-}]
-}
-tracks/3/type = "method"
-tracks/3/imported = false
-tracks/3/enabled = true
-tracks/3/path = NodePath("Counter")
-tracks/3/interp = 1
-tracks/3/loop_wrap = true
-tracks/3/keys = {
-"times": PackedFloat32Array(),
-"transitions": PackedFloat32Array(),
-"values": []
-}
-tracks/4/type = "method"
-tracks/4/imported = false
-tracks/4/enabled = true
-tracks/4/path = NodePath("Camera")
-tracks/4/interp = 1
-tracks/4/loop_wrap = true
-tracks/4/keys = {
-"times": PackedFloat32Array(3),
-"transitions": PackedFloat32Array(1),
-"values": [{
-"args": [],
-"method": &"make_current"
-}]
-}
-
-[sub_resource type="AnimationLibrary" id="AnimationLibrary_hplnw"]
-_data = {
-"RESET": SubResource("Animation_2si4r"),
-"count_in": SubResource("Animation_uaks0")
-}
-
-[node name="race" type="Node3D" node_paths=PackedStringArray("track", "splits", "timer")]
+[node name="race" type="Node3D"]
script = ExtResource("1_ckbwd")
car_scene = ExtResource("6_nu32e")
ghost_scene = ExtResource("3_cb3p0")
-track = NodePath("Track")
-splits = NodePath("CanvasLayer/Splits")
-timer = NodePath("CanvasLayer/HBoxContainer/Panel2/Timer")
-
-[node name="Track" parent="." instance=ExtResource("11_6q53c")]
-transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
-curve = ExtResource("5_yk721")
-track = ExtResource("6_506fu")
-
-[node name="Camera" type="Camera3D" parent="."]
-transform = Transform3D(0.226651, 0, -0.973976, 0, 1, 0, 0.973976, 0, 0.226651, -25.1963, 1.82268, -2.33777)
-far = 500.0
-script = ExtResource("5_nb035")
-target_distance = 9.0
-target_height = 4.0
+track_loader_scene = ExtResource("11_6q53c")
[node name="Env" type="WorldEnvironment" parent="."]
environment = ExtResource("2_pnp7e")
camera_attributes = ExtResource("3_jx550")
-[node name="Ground" type="StaticBody3D" parent="."]
-metadata/_edit_lock_ = true
-metadata/_edit_group_ = true
-
-[node name="CollisionShape" type="CollisionShape3D" parent="Ground"]
-shape = SubResource("WorldBoundaryShape3D_tkhh8")
-
-[node name="MeshInstance" type="MeshInstance3D" parent="Ground"]
-mesh = SubResource("PlaneMesh_ta0cd")
-
-[node name="CanvasLayer" type="CanvasLayer" parent="."]
-
-[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer"]
-anchors_preset = 12
-anchor_top = 1.0
-anchor_right = 1.0
-anchor_bottom = 1.0
-offset_top = -105.0
-grow_horizontal = 2
-grow_vertical = 0
-theme = ExtResource("7_6itw5")
-theme_override_constants/separation = 50
-alignment = 1
-
-[node name="Panel" type="PanelContainer" parent="CanvasLayer/HBoxContainer"]
-layout_mode = 2
-
-[node name="Speedometer" type="Label" parent="CanvasLayer/HBoxContainer/Panel"]
-custom_minimum_size = Vector2(0, 105)
-layout_mode = 2
-size_flags_horizontal = 4
-text = "龍 0km/h"
-horizontal_alignment = 1
-vertical_alignment = 1
-script = ExtResource("8_awr5n")
-
-[node name="Panel2" type="PanelContainer" parent="CanvasLayer/HBoxContainer"]
-layout_mode = 2
-
-[node name="Timer" type="Label" parent="CanvasLayer/HBoxContainer/Panel2"]
-custom_minimum_size = Vector2(0, 105)
-layout_mode = 2
-size_flags_horizontal = 4
-text = "祥 0:00:00"
-horizontal_alignment = 1
-vertical_alignment = 1
-script = ExtResource("9_dn61b")
-
-[node name="MiniMap" type="Line2D" parent="CanvasLayer" node_paths=PackedStringArray("track")]
-texture_repeat = 2
-width = 40.0
-default_color = Color(0.854902, 0.854902, 0.854902, 1)
-gradient = SubResource("Gradient_2kvil")
-texture = ExtResource("14_n0r0n")
-texture_mode = 1
-antialiased = true
-script = ExtResource("10_58kgt")
-track = NodePath("../../Track")
-player_color = Color(1, 0.388235, 0.321569, 1)
-finish_indicator = ExtResource("16_rp311")
-player_indicator = ExtResource("17_ptq57")
-ghost_indicator = ExtResource("18_v7a53")
-
-[node name="Splits" parent="CanvasLayer" instance=ExtResource("14_ge1w6")]
-visible = false
-
-[node name="Laps" type="PanelContainer" parent="CanvasLayer" node_paths=PackedStringArray("track", "label")]
-anchors_preset = 2
-anchor_top = 1.0
-anchor_bottom = 1.0
-offset_left = 10.0
-offset_top = -80.0
-offset_right = 105.0
-grow_vertical = 0
-theme = ExtResource("7_6itw5")
-script = ExtResource("16_mxur4")
-track = NodePath("../../Track")
-label = NodePath("Label")
-
-[node name="Label" type="Label" parent="CanvasLayer/Laps"]
-layout_mode = 2
-size_flags_horizontal = 4
-theme_override_font_sizes/font_size = 50
-text = " 1/3"
-horizontal_alignment = 1
-vertical_alignment = 1
-
-[node name="IntroCamera" type="Camera3D" parent="." node_paths=PackedStringArray("main_cam", "track", "count_player")]
-transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0)
-current = true
-far = 500.0
-script = ExtResource("14_yajvg")
-main_cam = NodePath("../Camera")
-track = NodePath("../Track")
-count_player = NodePath("../CountPlayer")
-
-[node name="Counter" type="RichTextLabel" parent="."]
-custom_minimum_size = Vector2(1400, 0)
-anchors_preset = 8
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-offset_left = -20.0
-offset_top = -20.0
-offset_right = 20.0
-offset_bottom = 20.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_colors/default_color = Color(0.980392, 0.737255, 0, 1)
-theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
-theme_override_constants/outline_size = 50
-theme_override_font_sizes/bold_font_size = 800
-bbcode_enabled = true
-text = "
-"
-fit_content = true
-
-[node name="CountPlayer" type="AnimationPlayer" parent="."]
-libraries = {
-"": SubResource("AnimationLibrary_hplnw")
-}
-
-[connection signal="created_car" from="." to="Camera" method="_on_race_created_car"]
-[connection signal="created_car" from="." to="CanvasLayer/HBoxContainer/Panel/Speedometer" method="_on_race_created_car"]
-[connection signal="created_car" from="." to="CanvasLayer/MiniMap" method="_on_race_created_car"]
-[connection signal="created_car" from="." to="IntroCamera" method="_on_race_created_car"]
-[connection signal="created_ghost" from="." to="CanvasLayer/MiniMap" method="_on_race_created_ghost"]
-[connection signal="next_lap" from="." to="CanvasLayer/Laps" method="increment"]
-[connection signal="race_started" from="IntroCamera" to="." method="_on_intro_camera_race_started"]
+[node name="Ground" parent="." instance=ExtResource("10_p60d8")]
diff --git a/scenes/floor.tscn b/scenes/floor.tscn
new file mode 100644
index 0000000..b000e39
--- /dev/null
+++ b/scenes/floor.tscn
@@ -0,0 +1,19 @@
+[gd_scene load_steps=4 format=3 uid="uid://cd4a5y0hi58ks"]
+
+[ext_resource type="Material" uid="uid://bdyn312e6c3ll" path="res://assets/mats/grass.tres" id="1_g7360"]
+
+[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_tkhh8"]
+
+[sub_resource type="PlaneMesh" id="PlaneMesh_ta0cd"]
+material = ExtResource("1_g7360")
+size = Vector2(5000, 5000)
+
+[node name="Ground" type="StaticBody3D"]
+metadata/_edit_lock_ = true
+metadata/_edit_group_ = true
+
+[node name="CollisionShape" type="CollisionShape3D" parent="."]
+shape = SubResource("WorldBoundaryShape3D_tkhh8")
+
+[node name="MeshInstance" type="MeshInstance3D" parent="."]
+mesh = SubResource("PlaneMesh_ta0cd")
diff --git a/scenes/race_high.tscn b/scenes/race_high.tscn
new file mode 100644
index 0000000..3c2a1a9
--- /dev/null
+++ b/scenes/race_high.tscn
@@ -0,0 +1,21 @@
+[gd_scene load_steps=5 format=3 uid="uid://calx1puxr4eng"]
+
+[ext_resource type="Script" path="res://scenes/race_highlevel.gd" id="1_q8hua"]
+[ext_resource type="PackedScene" uid="uid://cech6c4yrmcvq" path="res://race.tscn" id="2_q333e"]
+[ext_resource type="PackedScene" uid="uid://vok7fdcyec68" path="res://ui/hud.tscn" id="3_xp6f0"]
+[ext_resource type="PackedScene" uid="uid://clpo7rt0vkudy" path="res://ui/countdown.tscn" id="4_llox4"]
+
+[node name="race_high" type="Node"]
+script = ExtResource("1_q8hua")
+race_scene = ExtResource("2_q333e")
+hud_scene = ExtResource("3_xp6f0")
+countdown_scene = ExtResource("4_llox4")
+
+[node name="tester" type="ColorRect" parent="."]
+custom_minimum_size = Vector2(1920, 1038)
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+color = Color(0, 0, 0, 1)
diff --git a/scenes/race_highlevel.gd b/scenes/race_highlevel.gd
new file mode 100644
index 0000000..904a00b
--- /dev/null
+++ b/scenes/race_highlevel.gd
@@ -0,0 +1,29 @@
+extends Splitscreen
+
+@export var race_scene: PackedScene
+@export var hud_scene: PackedScene
+@export var countdown_scene: PackedScene
+
+var race: Race
+var huds: Array[HUD]
+
+func _ready() -> void:
+ race = race_scene.instantiate()
+ race.initialize(Globals.playing)
+ add_child(race)
+ add_player()
+ super()
+
+# cant call it join because of overriding and stuff
+func add_player() -> void:
+ var c_cam := CarCamera.new(race.car)
+ var i_cam := IntroCam.new(Globals.playing, c_cam)
+ var v := join()
+ v.viewport.add_child(c_cam)
+ v.viewport.add_child(i_cam)
+ var hud = hud_scene.instantiate()
+ hud.assigned.emit(race.car, race.ghost, race.timer, race.track)
+ v.add_child(hud)
+ race.split.connect(hud.splits.update)
+ race.next_lap.connect(hud.laps.increment)
+ i_cam.finished.connect(func(): var countdown := countdown_scene.instantiate(); v.add_child(countdown); countdown.finished.connect(func(): race.start()))
diff --git a/scenes/track-base.gd b/scenes/track-base.gd
index fdf2b7b..bffb716 100644
--- a/scenes/track-base.gd
+++ b/scenes/track-base.gd
@@ -111,10 +111,10 @@ func _update():
if track.laps == 1:
var s: Start = make_follower(track.start_scene, track.start_location, track.start_scale, track.start_needs_collision)
start_pos = s.global_position
- start_rot = s.rotation
+ start_rot = s.global_rotation
else:
start_pos = finish.global_position
- start_rot = finish.rotation
+ start_rot = finish.global_rotation
start_rot = start_rot.snapped(Vector3(PI/2, PI/2, PI/2))
# loopage
diff --git a/start.tscn b/start.tscn
index e5a8f9d..eb0c68a 100644
--- a/start.tscn
+++ b/start.tscn
@@ -1,6 +1,10 @@
-[gd_scene load_steps=2 format=3 uid="uid://bvfqaoqjsxj73"]
+[gd_scene load_steps=6 format=3 uid="uid://bvfqaoqjsxj73"]
[ext_resource type="Theme" uid="uid://ch2uo5qd8ubx6" path="res://ui/theme.tres" id="1_gm0ws"]
+[ext_resource type="Script" path="res://ui/tracks.gd" id="2_po2ce"]
+[ext_resource type="Resource" uid="uid://crye0ijvmtsyb" path="res://tracks/multilap_test.tres" id="3_0yjp1"]
+[ext_resource type="Resource" uid="uid://de46bcu1ivmtq" path="res://tracks/test.tres" id="4_3xqvr"]
+[ext_resource type="PackedScene" uid="uid://calx1puxr4eng" path="res://scenes/race_high.tscn" id="5_m5kci"]
[node name="start" type="Control"]
layout_mode = 3
@@ -11,20 +15,29 @@ grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_gm0ws")
-[node name="GridContainer" type="GridContainer" parent="."]
+[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 1
-anchors_preset = 8
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-offset_left = -11.5
-offset_top = -15.5
-offset_right = 11.5
-offset_bottom = 15.5
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
+theme_override_constants/margin_left = 50
+theme_override_constants/margin_top = 50
+theme_override_constants/margin_right = 50
+theme_override_constants/margin_bottom = 50
+
+[node name="TabContainer" type="TabContainer" parent="MarginContainer"]
+layout_mode = 2
+
+[node name="play" type="VBoxContainer" parent="MarginContainer/TabContainer"]
+layout_mode = 2
-[node name="Button" type="Button" parent="GridContainer"]
+[node name="tracks" type="GridContainer" parent="MarginContainer/TabContainer/play"]
layout_mode = 2
-text = "test"
+theme_override_constants/h_separation = 15
+theme_override_constants/v_separation = 15
+columns = 5
+script = ExtResource("2_po2ce")
+tracks = Array[Resource("res://classes/track.gd")]([ExtResource("3_0yjp1"), ExtResource("4_3xqvr")])
+race = ExtResource("5_m5kci")
diff --git a/tracks/multilap_test.tres b/tracks/multilap_test.tres
index 05ef141..8c7c586 100644
--- a/tracks/multilap_test.tres
+++ b/tracks/multilap_test.tres
@@ -23,7 +23,7 @@ name = "multilap test"
is_loop = true
offset = Vector3(0, 1, 0)
laps = 3
-checkpoints = PackedFloat32Array(0.2, 0.6)
+checkpoints = [0.2, 0.6]
checkpoint_scene = ExtResource("1_ehf5p")
checkpoint_scale = Vector3(1, 1, 1)
checkpoint_needs_collision = true
diff --git a/tracks/test.tres b/tracks/test.tres
index d19c967..1214bfe 100644
--- a/tracks/test.tres
+++ b/tracks/test.tres
@@ -22,7 +22,7 @@ name = "test"
is_loop = false
offset = Vector3(0, 1, 0)
laps = 1
-checkpoints = PackedFloat32Array(0.5)
+checkpoints = [0.5]
checkpoint_scene = ExtResource("1_ra7ed")
checkpoint_scale = Vector3(0.4, 0.4, 0.4)
checkpoint_needs_collision = true
diff --git a/ui/countdown.tscn b/ui/countdown.tscn
new file mode 100644
index 0000000..1ac3f00
--- /dev/null
+++ b/ui/countdown.tscn
@@ -0,0 +1,97 @@
+[gd_scene load_steps=5 format=3 uid="uid://clpo7rt0vkudy"]
+
+[sub_resource type="GDScript" id="GDScript_4shhd"]
+resource_name = "countdown"
+script/source = "extends CanvasLayer
+
+signal finished
+
+func finished_anim() -> void:
+ finished.emit()
+"
+
+[sub_resource type="Animation" id="Animation_2si4r"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Counter:text")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": ["
+"]
+}
+
+[sub_resource type="Animation" id="Animation_uaks0"]
+resource_name = "count_in"
+length = 3.0
+step = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Counter:text")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 1, 2, 3),
+"transitions": PackedFloat32Array(1, 1, 1, 1),
+"update": 1,
+"values": ["[center][b]3[/b][/center]", "[center][b]2[/b][/center]
+", "[center][b]1[/b][/center]
+", ""]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Counter:theme_override_colors/default_color")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0, 3),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [Color(1, 0.360784, 0.227451, 1), Color(0.980392, 0.737255, 0, 1)]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_hplnw"]
+_data = {
+"RESET": SubResource("Animation_2si4r"),
+"count_in": SubResource("Animation_uaks0")
+}
+
+[node name="Countdown" type="CanvasLayer"]
+script = SubResource("GDScript_4shhd")
+
+[node name="CountPlayer" type="AnimationPlayer" parent="."]
+autoplay = "count_in"
+libraries = {
+"": SubResource("AnimationLibrary_hplnw")
+}
+
+[node name="Counter" type="RichTextLabel" parent="."]
+custom_minimum_size = Vector2(1400, 0)
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -700.0
+offset_top = -20.0
+offset_right = 700.0
+offset_bottom = 20.0
+grow_horizontal = 2
+grow_vertical = 2
+theme_override_colors/default_color = Color(1, 0.360784, 0.227451, 1)
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 50
+theme_override_font_sizes/bold_font_size = 800
+bbcode_enabled = true
+text = "
+"
+fit_content = true
+
+[connection signal="animation_finished" from="CountPlayer" to="." method="finished_anim" unbinds=1]
diff --git a/ui/hud.gd b/ui/hud.gd
new file mode 100644
index 0000000..3dcdff5
--- /dev/null
+++ b/ui/hud.gd
@@ -0,0 +1,8 @@
+extends Node
+class_name HUD
+
+signal assigned(car: Car, ghost: GhostCar, timer: GameTimer, track: TrackLoader)
+signal next_lap
+
+@export var splits: Splits
+@export var laps: LapCounter \ No newline at end of file
diff --git a/ui/hud.tscn b/ui/hud.tscn
new file mode 100644
index 0000000..132a3b4
--- /dev/null
+++ b/ui/hud.tscn
@@ -0,0 +1,111 @@
+[gd_scene load_steps=13 format=3 uid="uid://vok7fdcyec68"]
+
+[ext_resource type="Theme" uid="uid://ch2uo5qd8ubx6" path="res://ui/theme.tres" id="1_ie2j2"]
+[ext_resource type="Script" path="res://ui/hud.gd" id="1_sfhpc"]
+[ext_resource type="Script" path="res://ui/speedometer.gd" id="2_cvi37"]
+[ext_resource type="Script" path="res://ui/timer.gd" id="3_poksb"]
+[ext_resource type="Texture2D" uid="uid://bfe4ytl0vjosb" path="res://ui/assets/line.png" id="4_o0swd"]
+[ext_resource type="Script" path="res://ui/map.gd" id="5_blxcm"]
+[ext_resource type="Texture2D" uid="uid://b3nmp7eyu0hjk" path="res://ui/assets/flag.png" id="6_ho2g6"]
+[ext_resource type="Texture2D" uid="uid://b6ad1yrgtg6qk" path="res://ui/assets/player_indicator.png" id="7_wv12s"]
+[ext_resource type="Texture2D" uid="uid://dkbrx7rpa8dvc" path="res://ui/assets/ghost.png" id="8_yfv7r"]
+[ext_resource type="PackedScene" uid="uid://nkh2xi7tnumc" path="res://ui/splits/splits.tscn" id="9_gtkqi"]
+[ext_resource type="Script" path="res://ui/laps.gd" id="10_78pxt"]
+
+[sub_resource type="Gradient" id="Gradient_2kvil"]
+offsets = PackedFloat32Array(0, 0.178744, 0.454106, 0.719807, 1)
+colors = PackedColorArray(0.85098, 0.85098, 0.85098, 1, 0.942823, 0.942823, 0.942822, 1, 0.868985, 0.868985, 0.868985, 1, 0.838897, 0.838897, 0.838897, 1, 0.85098, 0.85098, 0.85098, 1)
+
+[node name="HUD" type="Control" node_paths=PackedStringArray("splits", "laps")]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_sfhpc")
+splits = NodePath("Splits")
+laps = NodePath("Laps")
+
+[node name="Dashboard" type="HBoxContainer" parent="."]
+layout_mode = 1
+anchors_preset = 12
+anchor_top = 1.0
+anchor_right = 1.0
+anchor_bottom = 1.0
+offset_top = -105.0
+grow_horizontal = 2
+grow_vertical = 0
+theme = ExtResource("1_ie2j2")
+theme_override_constants/separation = 50
+alignment = 1
+
+[node name="Panel" type="PanelContainer" parent="Dashboard"]
+layout_mode = 2
+
+[node name="Speedometer" type="Label" parent="Dashboard/Panel"]
+custom_minimum_size = Vector2(0, 105)
+layout_mode = 2
+size_flags_horizontal = 4
+text = "龍 0km/h"
+horizontal_alignment = 1
+vertical_alignment = 1
+script = ExtResource("2_cvi37")
+
+[node name="Panel2" type="PanelContainer" parent="Dashboard"]
+layout_mode = 2
+
+[node name="Timer" type="Label" parent="Dashboard/Panel2"]
+custom_minimum_size = Vector2(0, 105)
+layout_mode = 2
+size_flags_horizontal = 4
+text = "祥 0:00:00"
+horizontal_alignment = 1
+vertical_alignment = 1
+script = ExtResource("3_poksb")
+
+[node name="MiniMap" type="Line2D" parent="."]
+texture_repeat = 2
+width = 40.0
+default_color = Color(0.854902, 0.854902, 0.854902, 1)
+gradient = SubResource("Gradient_2kvil")
+texture = ExtResource("4_o0swd")
+texture_mode = 1
+antialiased = true
+script = ExtResource("5_blxcm")
+player_color = Color(1, 0.388235, 0.321569, 1)
+finish_indicator = ExtResource("6_ho2g6")
+player_indicator = ExtResource("7_wv12s")
+ghost_indicator = ExtResource("8_yfv7r")
+
+[node name="Splits" parent="." instance=ExtResource("9_gtkqi")]
+visible = false
+layout_mode = 1
+offset_right = 25.0
+
+[node name="Laps" type="PanelContainer" parent="." node_paths=PackedStringArray("label")]
+layout_mode = 1
+anchors_preset = 2
+anchor_top = 1.0
+anchor_bottom = 1.0
+offset_left = 10.0
+offset_top = -80.0
+offset_right = 105.0
+grow_vertical = 0
+theme = ExtResource("1_ie2j2")
+script = ExtResource("10_78pxt")
+label = NodePath("Label")
+
+[node name="Label" type="Label" parent="Laps"]
+layout_mode = 2
+size_flags_horizontal = 4
+theme_override_font_sizes/font_size = 50
+text = " 1/3"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[connection signal="assigned" from="." to="MiniMap" method="assigned"]
+[connection signal="assigned" from="." to="Laps" method="assigned"]
+[connection signal="assigned" from="." to="Dashboard/Panel/Speedometer" method="car_assigned" unbinds=3]
+[connection signal="assigned" from="." to="Dashboard/Panel2/Timer" method="assigned" unbinds=1]
+[connection signal="next_lap" from="." to="Laps" method="increment"]
diff --git a/ui/intro_cam.gd b/ui/intro_cam.gd
index 9838855..2e8a8aa 100644
--- a/ui/intro_cam.gd
+++ b/ui/intro_cam.gd
@@ -1,29 +1,28 @@
extends Camera3D
+class_name IntroCam
-@export var main_cam: Camera3D
-@export var track: TrackLoader
-@export var count_player: AnimationPlayer
+signal finished
-signal race_started
+var track: TrackResource
+var main_cam: Camera3D
-var car: Car
+func _init(_track: TrackResource, _main_cam: Camera3D):
+ track = _track
+ main_cam = _main_cam
func _ready() -> void:
+ make_current()
var box := AABB()
- for point in track.track.track.get_baked_points():
- box = box.expand(point)
+ for i in track.track.point_count:
+ box = box.expand(track.track.get_point_position(i))
var box_center := box.get_center()
- var top_center := Vector3(box_center.x, track.track.overview_height, box_center.z)
+ var top_center := Vector3(box_center.x, track.overview_height, box_center.z)
global_position = top_center
+ global_rotation_degrees.x = -90
await get_tree().create_timer(2).timeout
var tween := get_tree().create_tween().set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
tween.tween_property(self, ^"global_position", main_cam.global_position, 2)
tween.tween_property(self, ^"global_rotation", main_cam.global_rotation, 1)
await tween.finished
- count_player.play(&"count_in", -1, 2)
- await count_player.animation_finished
- car.ball.freeze = false
- race_started.emit()
-
-func _on_race_created_car(_car: Car) -> void:
- car = _car
+ finished.emit()
+ main_cam.make_current()
diff --git a/ui/laps.gd b/ui/laps.gd
index c33a886..6e9865c 100644
--- a/ui/laps.gd
+++ b/ui/laps.gd
@@ -1,14 +1,16 @@
extends PanelContainer
+class_name LapCounter
-@export var track: TrackLoader
+var track: TrackLoader
@export var label: Label
var lap := 0
-func _ready() -> void:
- visible = track.track.laps > 1
- increment()
-
func increment() -> void:
lap += 1
label.text = " %d/%d" % [lap, track.track.laps]
+
+func assigned(_car, _ghost, _timer, _track: TrackLoader) -> void:
+ track = _track
+ visible = track.track.laps > 1
+ increment()
diff --git a/ui/map.gd b/ui/map.gd
index eae9f9e..d2f3204 100644
--- a/ui/map.gd
+++ b/ui/map.gd
@@ -2,7 +2,8 @@ extends Line2D
class_name MiniMap
var path := Path2D.new()
-@export var track: TrackLoader
+var track: TrackLoader
+
@export var player_color: Color
@export var finish_indicator: Texture
@export var player_indicator: Texture
@@ -37,10 +38,10 @@ func _process(_delta: float) -> void:
if !follower[0].rotates:
(follower[1] as Sprite2D).global_rotation = -follower[2].global_rotation.y - PI/2
-func vec(xy: float) -> Vector2:
- return Vector2(xy, xy)
-
func mkfollower(node: Node3D, tex: Texture, mod := Color.WHITE, back := false, rotates := false):
+ if !is_instance_valid(node):
+ push_warning("invalid follower")
+ return
var follower := PathFollow2D.new()
follower.rotates = rotates
path.add_child(follower)
@@ -56,8 +57,7 @@ func mkfollower(node: Node3D, tex: Texture, mod := Color.WHITE, back := false, r
func flatten(v: Vector3) -> Vector2:
return Vector2(v.x, v.z)
-func _on_race_created_car(car: Car) -> void:
+func assigned(car: Car, ghost: GhostCar, _timer, _track: TrackLoader) -> void:
mkfollower(car.car_mesh, player_indicator, player_color)
-
-func _on_race_created_ghost(ghost: GhostCar) -> void:
mkfollower(ghost, ghost_indicator, Color(1,1,1,.5), true)
+ track = _track
diff --git a/ui/speedometer.gd b/ui/speedometer.gd
index c7c93da..3e6b953 100644
--- a/ui/speedometer.gd
+++ b/ui/speedometer.gd
@@ -3,12 +3,8 @@ extends Label
@export var f_string = "龍 %dkm/h"
var car: Car
-func _ready() -> void:
- set_process(false)
-
func _process(_delta: float) -> void:
text = f_string % car.kph()
-func _on_race_created_car(_car: Car) -> void:
+func car_assigned(_car: Car) -> void:
car = _car
- set_process(true)
diff --git a/ui/splits/splits.gd b/ui/splits/splits.gd
index a446b37..8a160c6 100644
--- a/ui/splits/splits.gd
+++ b/ui/splits/splits.gd
@@ -1,4 +1,5 @@
extends VBoxContainer
+class_name Splits
@export var diff: PanelContainer
@export var current: Label
diff --git a/ui/timer.gd b/ui/timer.gd
index 3215521..a8a5b69 100644
--- a/ui/timer.gd
+++ b/ui/timer.gd
@@ -1,24 +1,9 @@
extends Label
-class_name GameTimer
-var elapsed_time: float = 0.0
+var timer: GameTimer
-func _ready() -> void:
- stop()
+func assigned(_car, _ghost, _timer: GameTimer) -> void:
+ timer = _timer
-func start() -> void:
- set_process(true)
-
-func stop() -> void:
- set_process(false)
-
-func now() -> float:
- return elapsed_time
-
-## format a number of seconds into m:s.ms
-static func format(time: float) -> String:
- return "%01d:%02d.%02d" % [time / 60, fmod(time, 60), fmod(time * 1000, 100)]
-
-func _process(delta: float) -> void:
- elapsed_time += delta
- text = "祥 %s" % GameTimer.format(elapsed_time) \ No newline at end of file
+func _process(_delta: float) -> void:
+ text = "祥 %s" % timer.fmt_now() \ No newline at end of file
diff --git a/ui/tracks.gd b/ui/tracks.gd
new file mode 100644
index 0000000..048167a
--- /dev/null
+++ b/ui/tracks.gd
@@ -0,0 +1,17 @@
+extends GridContainer
+
+@export var tracks: Array[TrackResource]
+@export var race: PackedScene
+
+func _ready() -> void:
+ for track in tracks:
+ var button := Button.new()
+ add_child(button)
+ button.name = track.name
+ button.text = track.name
+ button.pressed.connect(track_selected.bind(track))
+
+func track_selected(track: TrackResource) -> void:
+ print("play %s" % track.name)
+ Globals.playing = track
+ get_tree().change_scene_to_packed(race) \ No newline at end of file