small racing game im working on
saved trackdata
found out non deterministic physics, panicing sort of
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | classes/track.gd | 2 | ||||
| -rw-r--r-- | classes/trackdata.gd | 41 | ||||
| -rw-r--r-- | godot.lock | 7 | ||||
| -rw-r--r-- | godot.package | 2 | ||||
| -rw-r--r-- | race.gd | 56 | ||||
| -rw-r--r-- | race.tscn | 3 | ||||
| -rw-r--r-- | tracks/test.tres | 1 | ||||
| -rw-r--r-- | ui/intro_cam.gd | 3 | ||||
| -rw-r--r-- | ui/splits/difference.gd | 4 | ||||
| -rw-r--r-- | ui/timer.gd | 3 |
11 files changed, 105 insertions, 18 deletions
@@ -1,3 +1,4 @@ .godot/ movie.* *.blend1 +addons/ diff --git a/classes/track.gd b/classes/track.gd index 956fe39..c07ae6d 100644 --- a/classes/track.gd +++ b/classes/track.gd @@ -22,6 +22,8 @@ class_name TrackResource ## Sun y rotation ( its a game, the sun rotates around us ) @export_range(-360, 360) var sun_y := 0 @export_group("", "") +## The name of this track +@export var name: String = "" ## Does the track loop around? @export var is_loop := true ## Offset the entire track diff --git a/classes/trackdata.gd b/classes/trackdata.gd new file mode 100644 index 0000000..d516097 --- /dev/null +++ b/classes/trackdata.gd @@ -0,0 +1,41 @@ +class_name TrackSaveableData +extends RefCounted + +const SaveLoad := preload("res://addons/@bendn/remap/private/SaveLoadUtils.gd") + +var time: float +var checkpoints: PackedFloat32Array +var positional := { + origins = PackedVector3Array(), + rotations = PackedVector3Array() +} + +func data() -> Dictionary: + return ({time = time, checkpoints = checkpoints, positional = positional}) + +func _init(num_checkpoints: int) -> void: + checkpoints.resize(num_checkpoints) + checkpoints.fill(-1) + +func collect(cp: int, now: float) -> void: + if cp == -1: # fin + time = now + else: + checkpoints[cp] = now + +func snapshot(obj: Node3D) -> void: + positional.origins.append(obj.global_position) + positional.rotations.append(obj.global_rotation) + +static func from_d(d: Dictionary) -> TrackSaveableData: + var obj := TrackSaveableData.new(0) + obj.checkpoints = d.get("checkpoints", []) + obj.time = d.get("time", -1) + obj.positional = d.get("positional", {origins = null, rotations = null}) + return obj + +static func _load(path: String) -> TrackSaveableData: + var res := SaveLoad.load_file(path) + if res.is_empty(): + return null + return TrackSaveableData.from_d(res) diff --git a/godot.lock b/godot.lock new file mode 100644 index 0000000..dbc3f12 --- /dev/null +++ b/godot.lock @@ -0,0 +1,7 @@ +[ + { + "name": "@bendn/remap", + "version": "5.0.6", + "integrity": "sha512-lfB0Vx/fmXhnrTttiG+sr33EFAlAEopDq9lX2bn3z+pp3dzSuMtTaRwbkUN8ndbuwfPa8Dm+NghUX2s3wHQFLQ==" + } +]
\ No newline at end of file diff --git a/godot.package b/godot.package new file mode 100644 index 0000000..c9a13a2 --- /dev/null +++ b/godot.package @@ -0,0 +1,2 @@ +[packages] +"@bendn/remap" = '5.0.6' @@ -1,36 +1,58 @@ extends Node3D -@export var car: PackedScene +@export var car_scene: PackedScene @export var track: TrackLoader @export var splits: Control @export var timer: Control +@onready var data := TrackSaveableData.new(track.checkpoints.size()) +@onready var best_time_data := TrackSaveableData._load(saves % track.track.name) +var car: Node3D +var start_frame: int + +const SaveLoad := preload("res://addons/@bendn/remap/private/SaveLoadUtils.gd") +const saves := "user://%s.trackdata" signal created_car(car: Car) +signal finished func _ready() -> void: - var c: Node3D = car.instantiate() - c.set_script(load("res://classes/human_car.gd")) - c.show_debug = true - add_child(c) - c.ball.freeze = true - c.visible = false - c.global_position = track.start_pos + Vector3.UP * 3.5 - c.set_deferred(&"rotation", track.start_rot + Vector3.UP * PI) + car = car_scene.instantiate() + car.set_script(load("res://classes/human_car.gd")) + 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 - c.global_position = c.global_position - (c.ball.global_transform.basis.z * 2) # bump forward a teensy bit - c.visible = true - created_car.emit(c) + car.global_position = car.global_position - (car.ball.global_transform.basis.z * 2) # bump forward a teensy bit + car.visible = true + created_car.emit(car) for i in len(track.checkpoints): track.checkpoints[i].collected.connect(collect.bind(i)) track.finish.collected.connect( func passed_finish() -> void: - if track.checkpoints.size() == len(collected_checkpoints): - collect(-1) + for t in data.checkpoints: # no any() function on packedfloat32 + if t < 0: + return + collect(-1) + finished.emit() + if not best_time_data or data.time < best_time_data.time: + SaveLoad.save(saves % track.track.name, data.data()) + best_time_data = data + data = TrackSaveableData.new(track.checkpoints.size()) ) +func _physics_process(_delta: float) -> void: + data.snapshot(car.car_mesh) + + func collect(cp: int) -> void: - splits.update(timer.elapsed_time, 10) - collected_checkpoints.append(cp) + 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 + splits.update(timer.now(), time) + data.collect(cp, timer.now()) + -var collected_checkpoints: PackedInt32Array = [] +func _on_intro_camera_race_started() -> void: + start_frame = Engine.get_physics_frames() @@ -116,7 +116,7 @@ _data = { [node name="race" type="Node3D" node_paths=PackedStringArray("track", "splits", "timer")] script = ExtResource("1_ckbwd") -car = ExtResource("6_nu32e") +car_scene = ExtResource("6_nu32e") track = NodePath("Track") splits = NodePath("CanvasLayer/Splits") timer = NodePath("CanvasLayer/HBoxContainer/Panel2/Timer") @@ -237,3 +237,4 @@ 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="race_started" from="IntroCamera" to="." method="_on_intro_camera_race_started"] diff --git a/tracks/test.tres b/tracks/test.tres index 2f1ff99..504ef4b 100644 --- a/tracks/test.tres +++ b/tracks/test.tres @@ -17,6 +17,7 @@ left_barrier = true right_barrier = true sun_x = -90 sun_y = 0 +name = "test" is_loop = false offset = Vector3(0, 1, 0) laps = 0 diff --git a/ui/intro_cam.gd b/ui/intro_cam.gd index e1c3e60..26088d6 100644 --- a/ui/intro_cam.gd +++ b/ui/intro_cam.gd @@ -4,6 +4,8 @@ extends Camera3D @export var track: TrackLoader @export var count_player: AnimationPlayer +signal race_started + var car: Car func _ready() -> void: @@ -22,6 +24,7 @@ func _ready() -> void: 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 diff --git a/ui/splits/difference.gd b/ui/splits/difference.gd index 8d81ff3..ee5c910 100644 --- a/ui/splits/difference.gd +++ b/ui/splits/difference.gd @@ -8,6 +8,10 @@ extends PanelContainer enum Change { GAIN, LOSS, EQUAL } func update(time: float, prev_time: float) -> void: + if prev_time < 0: # no time set + hide() + else: + show() # shouldnt be needed but just to be carefull var change := diff(time, prev_time) style(change) match change: diff --git a/ui/timer.gd b/ui/timer.gd index 0895ecc..3215521 100644 --- a/ui/timer.gd +++ b/ui/timer.gd @@ -12,6 +12,9 @@ func start() -> void: 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)] |