small racing game im working on
-rw-r--r--classes/car.gd4
-rw-r--r--classes/trackdata.gd31
-rw-r--r--race.gd40
-rw-r--r--race.tscn34
-rw-r--r--scenes/ring_checkpoint.tscn10
-rw-r--r--tracks/multilap_test.tres (renamed from tracks/speedway_track.tres)19
-rw-r--r--tracks/multilap_test_curve.tres (renamed from tracks/speedway_curve.tres)0
-rw-r--r--ui/laps.gd14
-rw-r--r--ui/splits/difference.gd3
9 files changed, 113 insertions, 42 deletions
diff --git a/classes/car.gd b/classes/car.gd
index 133abff..05085a2 100644
--- a/classes/car.gd
+++ b/classes/car.gd
@@ -7,8 +7,8 @@ class_name Car
# mesh references
@onready var right_wheel := $CarMesh/frontright as MeshInstance3D
@onready var left_wheel := $CarMesh/frontleft as MeshInstance3D
-@onready var skid_l = $CarMesh/SkidL as GPUParticles3D
-@onready var skid_r = $CarMesh/SkidR as GPUParticles3D
+@onready var skid_l := $CarMesh/SkidL as GPUParticles3D
+@onready var skid_r := $CarMesh/SkidR as GPUParticles3D
@onready var body_mesh := $CarMesh/body as MeshInstance3D
@export var show_debug := false
diff --git a/classes/trackdata.gd b/classes/trackdata.gd
index e8a3914..3ac8175 100644
--- a/classes/trackdata.gd
+++ b/classes/trackdata.gd
@@ -1,10 +1,10 @@
class_name TrackSaveableData
-extends RefCounted
+extends Resource
const SaveLoad := preload("res://addons/@bendn/remap/private/SaveLoadUtils.gd")
var time: float
-var checkpoints: PackedFloat32Array
+var checkpoints: Array[PackedFloat32Array]
var positional := {
origins = PackedVector3Array(),
rotations = PackedVector3Array(),
@@ -15,15 +15,22 @@ var positional := {
func data() -> Dictionary:
return ({time = time, checkpoints = checkpoints, positional = positional})
-func _init(num_checkpoints: int) -> void:
- checkpoints.resize(num_checkpoints)
- checkpoints.fill(-1)
+func _init(num_checkpoints := 0, laps := 0) -> void:
+ for i in laps:
+ var arr: PackedFloat32Array = []
+ arr.resize(num_checkpoints + 1)
+ arr.fill(-1)
+ checkpoints.append(arr)
-func collect(cp: int, now: float) -> void:
- if cp == -1: # fin
+func collect(lap: int, cp: int, now: float) -> void:
+ if lap == len(checkpoints) - 1 && cp == -1:
+ checkpoints[lap][cp] = now
time = now
else:
- checkpoints[cp] = now
+ checkpoints[lap][cp] = now
+
+func get_time(lap: int, cp: int) -> float:
+ return checkpoints[lap][cp]
func snapshot(obj: Car) -> void:
positional.origins.append(obj.car_mesh.global_position)
@@ -38,10 +45,12 @@ func snaps() -> int:
return positional.snaps
static func from_d(d: Dictionary) -> TrackSaveableData:
+ if !d.has_all(["checkpoints", "positional", "time"]) and d.positional.has_all(["origins", "rotations", "steering", "snaps"]):
+ return null
var obj := TrackSaveableData.new(0)
- obj.checkpoints = d.get("checkpoints", [])
- obj.time = d.get("time", -1)
- obj.positional = d.get("positional", {origins = [], rotations = [], steering = [], snaps = 0})
+ obj.checkpoints = d.checkpoints
+ obj.time = d.time
+ obj.positional = d.positional
return obj
static func _load(path: String) -> TrackSaveableData:
diff --git a/race.gd b/race.gd
index 978e8dd..0404cc9 100644
--- a/race.gd
+++ b/race.gd
@@ -5,15 +5,18 @@ extends Node3D
@export var track: TrackLoader
@export var splits: Control
@export var timer: Control
-@onready var data := TrackSaveableData.new(track.checkpoints.size())
+@onready var data := TrackSaveableData.new(track.checkpoints.size(), track.track.laps)
@onready var best_time_data := TrackSaveableData._load(saves % track.track.name)
var car: Car
var ghost: GhostCar
+var current_lap := 0
var start_frame: int
+var playing := false
const SaveLoad := preload("res://addons/@bendn/remap/private/SaveLoadUtils.gd")
const saves := "user://%s.trackdata"
+signal next_lap
signal created_car(car: Car)
signal finished
@@ -42,21 +45,29 @@ func _ready() -> void:
created_car.emit(car)
print("car created")
for i in len(track.checkpoints):
- track.checkpoints[i].collected.connect(collect.bind(i))
+ 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:
- for t in data.checkpoints: # no any() function on packedfloat32
- if t < 0:
+ 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)
- finished.emit()
- 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())
+ if not track.track.laps or 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()
)
func _physics_process(_delta: float) -> void:
@@ -73,12 +84,13 @@ func _physics_process(_delta: float) -> void:
func collect(cp: int) -> void:
- var time := best_time_data.checkpoints[cp] if best_time_data else -1.0
- time = best_time_data.time if cp == -1 and time != -1.0 else time
+ 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)
- data.collect(cp, timer.now())
+ data.collect(current_lap, cp, timer.now())
func _on_intro_camera_race_started() -> void:
start_frame = Engine.get_physics_frames()
+ playing = true
set_physics_process(true)
diff --git a/race.tscn b/race.tscn
index 58f7783..271d867 100644
--- a/race.tscn
+++ b/race.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=22 format=3 uid="uid://dmkcxlevx4c7g"]
+[gd_scene load_steps=23 format=3 uid="uid://dmkcxlevx4c7g"]
[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"]
@@ -6,16 +6,17 @@
[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://clw61td2wh84w" path="res://scenes/track.tscn" id="11_6q53c"]
-[ext_resource type="Curve3D" uid="uid://cuonflkcdybj0" path="res://tracks/test_curve.tres" id="12_8yl7p"]
-[ext_resource type="Resource" uid="uid://de46bcu1ivmtq" path="res://tracks/test.tres" id="13_sh6e8"]
[ext_resource type="PackedScene" uid="uid://nkh2xi7tnumc" path="res://ui/splits/splits.tscn" id="14_ge1w6"]
[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"]
[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_tkhh8"]
@@ -125,8 +126,8 @@ 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("12_8yl7p")
-track = ExtResource("13_sh6e8")
+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)
@@ -199,6 +200,27 @@ player_color = Color(1, 0.388235, 0.321569, 0.803922)
[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
@@ -239,4 +261,6 @@ libraries = {
[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="finished" from="." to="CanvasLayer/Laps" method="increment"]
+[connection signal="next_lap" from="." to="CanvasLayer/Laps" method="increment"]
[connection signal="race_started" from="IntroCamera" to="." method="_on_intro_camera_race_started"]
diff --git a/scenes/ring_checkpoint.tscn b/scenes/ring_checkpoint.tscn
index eae51f3..c85070c 100644
--- a/scenes/ring_checkpoint.tscn
+++ b/scenes/ring_checkpoint.tscn
@@ -3,13 +3,13 @@
[ext_resource type="Script" path="res://scenes/ring_checkpoint.gd" id="1_cmmpp"]
[ext_resource type="TorusMesh" uid="uid://dlbpusye3e33p" path="res://assets/meshes/checkpoint.tres" id="2_xys6y"]
-[sub_resource type="TorusMesh" id="TorusMesh_wt6vi"]
+[sub_resource type="TorusMesh" id="TorusMesh_mi087"]
inner_radius = 25.0
outer_radius = 40.0
rings = 10
ring_segments = 4
-[sub_resource type="BoxShape3D" id="BoxShape3D_2btqs"]
+[sub_resource type="BoxShape3D" id="BoxShape3D_k77jm"]
size = Vector3(52, 52, 3)
[node name="Checkpoint" type="PathFollow3D"]
@@ -24,7 +24,7 @@ mesh = ExtResource("2_xys6y")
transform = Transform3D(1, 0, 0, 0, 1, -8.35187e-23, 0, -8.35187e-23, 1, 0, 0, 0)
visible = false
use_collision = true
-mesh = SubResource("TorusMesh_wt6vi")
+mesh = SubResource("TorusMesh_mi087")
[node name="PlayerDetector" type="Area3D" parent="."]
collision_layer = 0
@@ -32,6 +32,6 @@ collision_mask = 2
monitorable = false
[node name="Area" type="CollisionShape3D" parent="PlayerDetector"]
-shape = SubResource("BoxShape3D_2btqs")
+shape = SubResource("BoxShape3D_k77jm")
-[connection signal="body_entered" from="PlayerDetector" to="." method="enter" flags=6 unbinds=1]
+[connection signal="body_entered" from="PlayerDetector" to="." method="enter" unbinds=1]
diff --git a/tracks/speedway_track.tres b/tracks/multilap_test.tres
index 9ee2d5e..b8894b9 100644
--- a/tracks/speedway_track.tres
+++ b/tracks/multilap_test.tres
@@ -1,9 +1,10 @@
-[gd_resource type="Resource" script_class="TrackResource" load_steps=5 format=3 uid="uid://busubw34xl76"]
+[gd_resource type="Resource" script_class="TrackResource" load_steps=6 format=3 uid="uid://crye0ijvmtsyb"]
[ext_resource type="Script" path="res://classes/track.gd" id="1_c5h3o"]
[ext_resource type="PackedScene" uid="uid://d4a3e1w62m3ck" path="res://scenes/ring_checkpoint.tscn" id="1_ehf5p"]
-[ext_resource type="Curve3D" uid="uid://u2f56xx8h2re" path="res://tracks/speedway_curve.tres" id="2_33qpi"]
+[ext_resource type="Curve3D" uid="uid://u2f56xx8h2re" path="res://tracks/multilap_test_curve.tres" id="2_33qpi"]
[ext_resource type="PackedScene" uid="uid://t8ywjcjgw322" path="res://scenes/ring_finish.tscn" id="2_lfdrw"]
+[ext_resource type="PackedScene" uid="uid://bsftidvcmsha0" path="res://scenes/ring_start.tscn" id="4_awtsk"]
[resource]
resource_local_to_scene = true
@@ -15,11 +16,21 @@ support_height = 2.0
track = ExtResource("2_33qpi")
left_barrier = true
right_barrier = true
-sun_x = -90
+sun_x = -50
sun_y = 0
+name = "multilap test"
+is_loop = true
offset = Vector3(0, 1, 0)
+laps = 3
checkpoints = PackedFloat32Array(0.2, 0.6)
checkpoint_scene = ExtResource("1_ehf5p")
+checkpoint_scale = Vector3(1, 1, 1)
+checkpoint_needs_collision = true
finish_location = 0.0
finish_scene = ExtResource("2_lfdrw")
-laps = 0
+finish_scale = Vector3(1, 1, 1)
+finish_needs_collision = true
+start_location = 0.0
+start_scene = ExtResource("4_awtsk")
+start_scale = Vector3(1, 1, 1)
+start_needs_collision = true
diff --git a/tracks/speedway_curve.tres b/tracks/multilap_test_curve.tres
index 2523886..2523886 100644
--- a/tracks/speedway_curve.tres
+++ b/tracks/multilap_test_curve.tres
diff --git a/ui/laps.gd b/ui/laps.gd
new file mode 100644
index 0000000..9189a17
--- /dev/null
+++ b/ui/laps.gd
@@ -0,0 +1,14 @@
+extends PanelContainer
+
+@export var track: TrackLoader
+@export var label: Label
+
+var lap := 0
+
+func _ready() -> void:
+ visible = track.track.laps
+ increment()
+
+func increment() -> void:
+ lap += 1
+ label.text = " %d/%d" % [lap, track.track.laps]
diff --git a/ui/splits/difference.gd b/ui/splits/difference.gd
index ee5c910..c9d33eb 100644
--- a/ui/splits/difference.gd
+++ b/ui/splits/difference.gd
@@ -10,6 +10,7 @@ enum Change { GAIN, LOSS, EQUAL }
func update(time: float, prev_time: float) -> void:
if prev_time < 0: # no time set
hide()
+ return
else:
show() # shouldnt be needed but just to be carefull
var change := diff(time, prev_time)
@@ -20,7 +21,7 @@ func update(time: float, prev_time: float) -> void:
Change.EQUAL: label.text = "0:00.00"
func diff(t1: float, t2: float) -> int:
- if t1 == t2:
+ if is_equal_approx(t1, t2):
return Change.EQUAL
return Change.GAIN if t1 < t2 else Change.LOSS