small racing game im working on
thumbnails
| -rw-r--r-- | .vscode/settings.json | 3 | ||||
| -rw-r--r-- | classes/car_vars.gd | 40 | ||||
| -rw-r--r-- | classes/resources/car_vars.gd | 40 | ||||
| -rw-r--r-- | classes/resources/ghost_data.gd (renamed from classes/ghost_data.gd) | 0 | ||||
| -rw-r--r-- | init_classes.py | 33 | ||||
| -rw-r--r-- | lib/activation.gd | 9 | ||||
| -rw-r--r-- | lib/matrix.gd | 148 | ||||
| -rw-r--r-- | lib/neural_network.gd | 127 | ||||
| -rw-r--r-- | start.tscn | 6 | ||||
| -rw-r--r-- | tracks/multilap_test.tres | 2 | ||||
| -rw-r--r-- | tracks/test.tres | 2 | ||||
| -rw-r--r-- | tracks/the fallen tramps.tres | 2 | ||||
| -rw-r--r-- | ui/hud.tscn | 3 | ||||
| -rw-r--r-- | ui/intro_cam.gd | 17 | ||||
| -rw-r--r-- | ui/track_button.tscn | 74 | ||||
| -rw-r--r-- | ui/trackbutton.gd | 39 | ||||
| -rw-r--r-- | ui/tracks.gd | 2 |
17 files changed, 188 insertions, 359 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index d773226..c9596d0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "godot_tools.gdscript_lsp_server_port": 6005 + "godot_tools.gdscript_lsp_server_port": 6005, + "python.formatting.provider": "black" } diff --git a/classes/car_vars.gd b/classes/car_vars.gd deleted file mode 100644 index dff1820..0000000 --- a/classes/car_vars.gd +++ /dev/null @@ -1,40 +0,0 @@ -class_name CarVars -extends Resource - -var throttle: float -var brake: float -var steering: float -var engine_force: float -var engine_rpm: float -var wheel_rpm: float -var wheel_skidinfo: Array -var wheel_contact: Array -var wheel_position: Array -var current_gear: int -var position: Vector3 -var rotation: Vector3 -var kph: float - -func _init(from: Car) -> void: - throttle = from.throttle - brake = from.brake - steering = from.steering - engine_force = from.engine_force - engine_rpm = from.engine_rpm - position = from.global_position - rotation = from.global_rotation - kph = from.kph() - for i in from.wheels.size(): - var wheel := from.wheels[i] - wheel_skidinfo.append(wheel.get_skidinfo()) - wheel_contact.append(wheel.is_in_contact()) - wheel_position.append(wheel.global_position) - -func to_dict(): # RIP memory - return { - throttle = throttle, brake = brake, steering = steering, - engine_force = engine_force, engine_rpm = engine_rpm, - position = position, rotation = rotation, kph = kph, - wheel_skidinfo = wheel_skidinfo, wheel_contact = wheel_contact, - wheel_position = wheel_position, - } diff --git a/classes/resources/car_vars.gd b/classes/resources/car_vars.gd new file mode 100644 index 0000000..2854034 --- /dev/null +++ b/classes/resources/car_vars.gd @@ -0,0 +1,40 @@ +class_name CarVars +extends Resource + +var throttle: float +var brake: float +var steering: float +var engine_force: float +var engine_rpm: float +var wheel_rpm: float +var wheel_skidinfo: Array +var wheel_contact: Array +var wheel_position: Array +var current_gear: int +var position: Vector3 +var rotation: Vector3 +var kph: float + +func _init(from: Car) -> void: + throttle = from.throttle + brake = from.brake + steering = from.steering + engine_force = from.engine_force + engine_rpm = from.engine_rpm + position = from.global_position + rotation = from.global_rotation + kph = from.kph() + for i in from.wheels.size(): + var wheel := from.wheels[i] + wheel_skidinfo.append(wheel.get_skidinfo()) + wheel_contact.append(wheel.is_in_contact()) + wheel_position.append(wheel.global_position) + +func to_dict(): # RIP memory + return { + throttle = throttle, brake = brake, steering = steering, + engine_force = engine_force, engine_rpm = engine_rpm, + position = position, rotation = rotation, kph = kph, + wheel_skidinfo = wheel_skidinfo, wheel_contact = wheel_contact, + wheel_position = wheel_position, + } diff --git a/classes/ghost_data.gd b/classes/resources/ghost_data.gd index 7be0426..7be0426 100644 --- a/classes/ghost_data.gd +++ b/classes/resources/ghost_data.gd diff --git a/init_classes.py b/init_classes.py new file mode 100644 index 0000000..29d1487 --- /dev/null +++ b/init_classes.py @@ -0,0 +1,33 @@ +import re +from glob import glob + +find_class = re.compile("class_name\s+(.+)") +find_base = re.compile("extends\s+(.+)") +classes = [] # { file, class name, base class name } + +for file in glob("**/*.gd", recursive=True): + with open(file, "r") as f: + text = f"{f.readline()}\n{f.readline()}\n{f.readline()}" # 3 lines: extend, class, tool + m = find_class.search(text) + if not m: + continue + class_name = m.groups()[0] + m = find_base.search(text) + base = m.groups()[0] + classes.append( + {"class_name": class_name, "base_class_name": base, "file": file} + ) + +first = True +print("list=[", end="") +for c in classes: + if not first: + print(", ", end="") + first = False + print("{") + print(f'"base": "{c["base_class_name"]}",') + print(f'"class": &"{c["class_name"]}",') + print('"language": &"GDScript",') + print(f'"path": "res://{c["file"]}"') + print("}", end="") +print("]") diff --git a/lib/activation.gd b/lib/activation.gd deleted file mode 100644 index 1db7637..0000000 --- a/lib/activation.gd +++ /dev/null @@ -1,9 +0,0 @@ -class_name Activation - - -static func sigmoid(value: float, _row: int, _col: int) -> float: - return 1 / (1 + exp(-value)) - - -static func dsigmoid(value: float, _row: int, _col: int) -> float: - return value * (1 - value) diff --git a/lib/matrix.gd b/lib/matrix.gd deleted file mode 100644 index f33103a..0000000 --- a/lib/matrix.gd +++ /dev/null @@ -1,148 +0,0 @@ -## Matrix calculations. -## -## This class allows to perform all the basic operations with matrices. -## (add, sub, multiply, scalar, dot product) -## It is also possible to import and export matrices from an array. -class_name Matrix - -var rows: int -var cols: int - -var data = [] - - -func _init(_rows: int,_cols: int,value: float = 0.0): - randomize() - rows = _rows - cols = _cols - for row in range(rows): - data.insert(row , []) - for col in range(cols): - data[row].insert(col, value) - - -static func from_array(arr: Array[float]) -> Matrix: - var result = Matrix.new(arr.size(), 1) - for row in range(result.rows): - result.data[row][0] = arr[row] - - return result - - -static func to_array(matrix: Matrix) -> Array[float]: - var result = [] - for row in range(matrix.rows): - for col in range(matrix.cols): - result.append(matrix.data[row][col]) - - return result - - -static func rand(matrix: Matrix) -> Matrix: - randomize() - - var result = Matrix.new(matrix.rows, matrix.cols) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = randf_range(-1, 1) - - return result - - -static func add(a: Matrix, b: Matrix) -> Matrix: - assert(a.rows == b.rows and a.cols == b.cols) - - var result = Matrix.new(a.rows, a.cols) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = a.data[row][col] + b.data[row][col] - - return result - - -static func subtract(a: Matrix, b: Matrix) -> Matrix: - assert(a.rows == b.rows and a.cols == b.cols) - - var result = Matrix.new(a.rows, a.cols) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = a.data[row][col] - b.data[row][col] - - return result - - -static func scalar(matrix: Matrix, value: float) -> Matrix: - var result = Matrix.new(matrix.rows, matrix.cols) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = matrix.data[row][col] * value - - return result - - -static func product(a: Matrix, b: Matrix) -> Matrix: - assert(a.cols == b.rows) - - var result = Matrix.new(a.rows, b.cols) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = 0.0 - for k in range(a.cols): - result.data[row][col] += a.data[row][k] * b.data[k][col] - - return result - - -static func multiply(a: Matrix, b: Matrix) -> Matrix: - assert(a.rows == b.rows and a.cols == b.cols) - - var result = Matrix.new(a.rows, a.cols) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = a.data[row][col] * b.data[row][col] - - return result - - -static func random(a: Matrix, b: Matrix) -> Matrix: - randomize() - var result = Matrix.new(a.rows, a.cols) - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = a.data[row][col] if randf_range(0, 1) > 0.5 else b.data[row][col] - - return result - - -static func transpose(matrix: Matrix) -> Matrix: - var result = Matrix.new(matrix.cols, matrix.rows) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = matrix.data[col][row] - - return result - - -static func copy(matrix: Matrix) -> Matrix: - var result = Matrix.new(matrix.rows, matrix.cols) - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = matrix.data[row][col] - return result - - -static func map(matrix: Matrix, callback) -> Matrix: - var result = Matrix.new(matrix.rows, matrix.cols) - - for row in range(result.rows): - for col in range(result.cols): - result.data[row][col] = callback.call(matrix.data[row][col], row, col) - - return result diff --git a/lib/neural_network.gd b/lib/neural_network.gd deleted file mode 100644 index 70c49f6..0000000 --- a/lib/neural_network.gd +++ /dev/null @@ -1,127 +0,0 @@ -## Neural network -## -## It is a basic neural network with three layers (input, hidden and output). -## The network is randomly initialized, it is possible to train it by passing it -## the expected result for some input. -class_name NeuralNetwork - -var input_nodes: int -var hidden_nodes: int -var output_nodes: int - -var weights_input_hidden: Matrix -var weights_hidden_output: Matrix - -var bias_hidden: Matrix -var bias_output: Matrix - -var learning_rate: float - -var activation_function: Callable -var activation_dfunction: Callable - - -func _init(_input_nodes: int,_hidden_nodes: int,_output_nodes: int): - input_nodes = _input_nodes; - hidden_nodes = _hidden_nodes; - output_nodes = _output_nodes; - - weights_input_hidden = Matrix.rand(Matrix.new(hidden_nodes, input_nodes)) - weights_hidden_output = Matrix.rand(Matrix.new(output_nodes, hidden_nodes)); - - bias_hidden = Matrix.rand(Matrix.new(hidden_nodes, 1)); - bias_output = Matrix.rand(Matrix.new(output_nodes, 1)); - - set_learning_rate() - set_activation_function() - - -func set_learning_rate(_learning_rate: float = 0.1) -> void: - learning_rate = _learning_rate - - -func set_activation_function(callback: Callable = Callable(Activation, "sigmoid"), dcallback: Callable = Callable(Activation, "dsigmoid")) -> void: - activation_function = callback - activation_dfunction = dcallback - - -func predict(input_array: Array[float]) -> Array[float]: - var inputs := Matrix.from_array(input_array) - - var hidden := Matrix.product(weights_input_hidden, inputs) - hidden = Matrix.add(hidden, bias_hidden) - hidden = Matrix.map(hidden, activation_function) - - var output = Matrix.product(weights_hidden_output, hidden) - output = Matrix.add(output, bias_output) - output = Matrix.map(output, activation_function) - - return Matrix.to_array(output) - - -func train(input_array: Array[float], target_array: Array[float]): - var inputs := Matrix.from_array(input_array) - var targets := Matrix.from_array(target_array) - - var hidden := Matrix.product(weights_input_hidden, inputs); - hidden = Matrix.add(hidden, bias_hidden) - hidden = Matrix.map(hidden, activation_function) - - var outputs := Matrix.product(weights_hidden_output, hidden) - outputs = Matrix.add(outputs, bias_output) - outputs = Matrix.map(outputs, activation_function) - - var output_errors = Matrix.subtract(targets, outputs) - - var gradients = Matrix.map(outputs, activation_dfunction) - gradients = Matrix.multiply(gradients, output_errors) - gradients = Matrix.scalar(gradients, learning_rate) - - var hidden_t = Matrix.transpose(hidden) - var weight_ho_deltas = Matrix.product(gradients, hidden_t) - - weights_hidden_output = Matrix.add(weights_hidden_output, weight_ho_deltas) - bias_output = Matrix.add(bias_output, gradients) - - var weights_hidden_output_t = Matrix.transpose(weights_hidden_output) - var hidden_errors = Matrix.product(weights_hidden_output_t, output_errors) - - var hidden_gradient = Matrix.map(hidden, activation_dfunction) - hidden_gradient = Matrix.multiply(hidden_gradient, hidden_errors) - hidden_gradient = Matrix.scalar(hidden_gradient, learning_rate) - - var inputs_t = Matrix.transpose(inputs) - var weight_ih_deltas = Matrix.product(hidden_gradient, inputs_t) - - weights_input_hidden = Matrix.add(weights_input_hidden, weight_ih_deltas) - - bias_hidden = Matrix.add(bias_hidden, hidden_gradient) - - -static func reproduce(a: NeuralNetwork, b: NeuralNetwork) -> NeuralNetwork: - var result = NeuralNetwork.new(a.input_nodes, a.hidden_nodes, a.output_nodes) - - result.weights_input_hidden = Matrix.random(a.weights_input_hidden, b.weights_input_hidden) - result.weights_hidden_output = Matrix.random(a.weights_hidden_output, b.weights_hidden_output) - result.bias_hidden = Matrix.random(a.bias_hidden, b.bias_hidden) - result.bias_output = Matrix.random(a.bias_output, b.bias_output) - - return result - - -static func mutate(nn: NeuralNetwork, callback: Callable) -> NeuralNetwork: - var result = NeuralNetwork.new(nn.input_nodes, nn.hidden_nodes, nn.output_nodes) - result.weights_input_hidden = Matrix.map(nn.weights_input_hidden, callback) - result.weights_hidden_output = Matrix.map(nn.weights_hidden_output, callback) - result.bias_hidden = Matrix.map(nn.bias_hidden, callback) - result.bias_output = Matrix.map(nn.bias_output, callback) - return result - - -static func copy(nn : NeuralNetwork) -> NeuralNetwork: - var result = NeuralNetwork.new(nn.input_nodes, nn.hidden_nodes, nn.output_nodes) - result.weights_input_hidden = Matrix.copy(nn.weights_input_hidden) - result.weights_hidden_output = Matrix.copy(nn.weights_hidden_output) - result.bias_hidden = Matrix.copy(nn.bias_hidden) - result.bias_output = Matrix.copy(nn.bias_output) - return result @@ -2,10 +2,10 @@ [ext_resource type="Theme" uid="uid://cru1d7n2ftrfm" 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="Resource" path="res://tracks/multilap_test.tres" id="3_0yjp1"] +[ext_resource type="Resource" path="res://tracks/test.tres" id="4_3xqvr"] [ext_resource type="PackedScene" uid="uid://dhiei0g5tr74s" path="res://scenes/race_high.tscn" id="5_m5kci"] -[ext_resource type="Resource" uid="uid://crtutccbf1sxh" path="res://tracks/the fallen tramps.tres" id="5_qwie6"] +[ext_resource type="Resource" path="res://tracks/the fallen tramps.tres" id="5_qwie6"] [ext_resource type="PackedScene" uid="uid://dfvtugujgcjcw" path="res://ui/track_button.tscn" id="7_pchkj"] [node name="start" type="Control"] diff --git a/tracks/multilap_test.tres b/tracks/multilap_test.tres index 298fba4..1f66712 100644 --- a/tracks/multilap_test.tres +++ b/tracks/multilap_test.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" script_class="TrackResource" load_steps=6 format=3 uid="uid://crye0ijvmtsyb"] +[gd_resource type="Resource" script_class="TrackResource" load_steps=6 format=3] [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"] diff --git a/tracks/test.tres b/tracks/test.tres index b30bdca..a22f705 100644 --- a/tracks/test.tres +++ b/tracks/test.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" script_class="TrackResource" load_steps=6 format=3 uid="uid://de46bcu1ivmtq"] +[gd_resource type="Resource" script_class="TrackResource" load_steps=6 format=3] [ext_resource type="PackedScene" uid="uid://d4a3e1w62m3ck" path="res://scenes/ring_checkpoint.tscn" id="1_ra7ed"] [ext_resource type="PackedScene" uid="uid://t8ywjcjgw322" path="res://scenes/ring_finish.tscn" id="2_e22em"] diff --git a/tracks/the fallen tramps.tres b/tracks/the fallen tramps.tres index ed4cfb6..e87daa0 100644 --- a/tracks/the fallen tramps.tres +++ b/tracks/the fallen tramps.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" script_class="TrackResource" load_steps=6 format=3 uid="uid://crtutccbf1sxh"] +[gd_resource type="Resource" script_class="TrackResource" load_steps=6 format=3] [ext_resource type="PackedScene" uid="uid://d4a3e1w62m3ck" path="res://scenes/ring_checkpoint.tscn" id="1_i8s2b"] [ext_resource type="PackedScene" uid="uid://t8ywjcjgw322" path="res://scenes/ring_finish.tscn" id="2_107h2"] diff --git a/ui/hud.tscn b/ui/hud.tscn index d6ccf3e..8ac3f5b 100644 --- a/ui/hud.tscn +++ b/ui/hud.tscn @@ -151,7 +151,8 @@ ghost_indicator = ExtResource("8_yfv7r") [node name="Splits" parent="." instance=ExtResource("9_gtkqi")] layout_mode = 1 -offset_right = 25.0 +offset_top = -403.0 +offset_bottom = -303.0 [connection signal="assigned" from="." to="Dashboard/laps" method="assigned"] [connection signal="assigned" from="." to="MiniMapContainer/MiniMap" method="assigned"] diff --git a/ui/intro_cam.gd b/ui/intro_cam.gd index c8371ac..ee2d7f5 100644 --- a/ui/intro_cam.gd +++ b/ui/intro_cam.gd @@ -6,11 +6,13 @@ signal finished var track: TrackResource var main_cam: Camera3D +# if main_cam null, dont animate func _init(_track: TrackResource, _main_cam: Camera3D): far = 4000 near = .2 track = _track main_cam = _main_cam + attributes = CameraAttributesPractical.new() func _ready() -> void: make_current() @@ -21,10 +23,11 @@ func _ready() -> void: 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 - finished.emit() - main_cam.make_current() + if is_instance_valid(main_cam): + 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 + finished.emit() + main_cam.make_current() diff --git a/ui/track_button.tscn b/ui/track_button.tscn index e4652cb..a54c48e 100644 --- a/ui/track_button.tscn +++ b/ui/track_button.tscn @@ -1,43 +1,89 @@ -[gd_scene load_steps=6 format=3 uid="uid://dfvtugujgcjcw"] +[gd_scene load_steps=8 format=3 uid="uid://dfvtugujgcjcw"] +[ext_resource type="Theme" uid="uid://cru1d7n2ftrfm" path="res://ui/theme.tres" id="1_noykn"] [ext_resource type="Script" path="res://ui/trackbutton.gd" id="2_bcpuy"] [ext_resource type="FontVariation" uid="uid://ba8ab6dti2fvo" path="res://ui/boldsans.tres" id="2_gctvu"] [ext_resource type="SystemFont" uid="uid://d2klp6vxh5l2d" path="res://ui/cascadiabold.tres" id="3_suph6"] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fymg3"] +bg_color = Color(0.137255, 0.137255, 0.137255, 1) + [sub_resource type="LabelSettings" id="LabelSettings_sa0e6"] font = ExtResource("2_gctvu") -font_size = 45 +font_size = 25 font_color = Color(0.933333, 0.909804, 0.835294, 1) [sub_resource type="LabelSettings" id="LabelSettings_7u0yx"] font = ExtResource("3_suph6") -font_size = 45 +font_size = 25 font_color = Color(0.933333, 0.909804, 0.835294, 1) -[node name="trackbutton" type="Button"] -custom_minimum_size = Vector2(450, 150) +[node name="trackbutton" type="PanelContainer"] +custom_minimum_size = Vector2(450, 243) offset_right = 200.0 offset_bottom = 100.0 +theme = ExtResource("1_noykn") +theme_override_styles/panel = SubResource("StyleBoxFlat_fymg3") script = ExtResource("2_bcpuy") -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 +[node name="port" type="SubViewport" parent="."] +unique_name_in_owner = true +msaa_3d = 3 +screen_space_aa = 1 +size = Vector2i(450, 200) +render_target_update_mode = 1 + +[node name="v" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="h" type="HBoxContainer" parent="v"] +layout_mode = 2 mouse_filter = 2 +theme_override_constants/separation = 10 alignment = 1 -[node name="name" type="Label" parent="VBoxContainer"] +[node name="name" type="Label" parent="v/h"] +unique_name_in_owner = true layout_mode = 2 text = "trambler 42" label_settings = SubResource("LabelSettings_sa0e6") horizontal_alignment = 1 -[node name="time" type="Label" parent="VBoxContainer"] +[node name="bar" type="Label" parent="v/h"] +layout_mode = 2 +text = "|" +label_settings = SubResource("LabelSettings_sa0e6") +horizontal_alignment = 1 + +[node name="time" type="Label" parent="v/h"] +unique_name_in_owner = true layout_mode = 2 text = "no time set" label_settings = SubResource("LabelSettings_7u0yx") horizontal_alignment = 1 + +[node name="thumb" type="TextureRect" parent="v"] +unique_name_in_owner = true +custom_minimum_size = Vector2(450, 200) +layout_mode = 2 +stretch_mode = 2 + +[node name="h2" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 8 + +[node name="play" type="Button" parent="h2"] +layout_mode = 2 +theme_override_font_sizes/font_size = 35 +text = " " + +[node name="spacer" type="Control" parent="h2"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="watch" type="Button" parent="h2"] +layout_mode = 2 +theme_override_font_sizes/font_size = 35 +text = " " + +[connection signal="pressed" from="h2/play" to="." method="emit_signal" binds= [&"pressed"]] diff --git a/ui/trackbutton.gd b/ui/trackbutton.gd index c046098..35f211f 100644 --- a/ui/trackbutton.gd +++ b/ui/trackbutton.gd @@ -1,8 +1,37 @@ extends Control -func init(t: float, n: String) -> void: - $VBoxContainer/name.text = n - if t < 0: - $VBoxContainer/time.text = "no time set" +const trackloader_scn = preload("res://scenes/track.tscn") +const thumbnail_path = "user://%s.thumb" + +signal pressed + +func init(t: TrackResource, g: GhostData) -> void: + %name.text = t.name + if g == null: + %time.text = "no time set" + else: + %time.text = GameTimer.format_precise(g.time) + var p: String = thumbnail_path % t.name + if FileAccess.file_exists(p) and Time.get_unix_time_from_system() - FileAccess.get_modified_time(p) < 40000: # ~5days + print("loading thumb") + var f := FileAccess.open(p, FileAccess.READ) + var img := Image.new() + var e := img.load_png_from_buffer(f.get_buffer(f.get_length())) + if e != OK: + print("error: ", e) + return + (%thumb as TextureRect).texture = ImageTexture.create_from_image(img) else: - $VBoxContainer/time.text = GameTimer.format_precise(t) + print("making thumb") + %port.add_child(IntroCam.new(t, null)) + var trackloader: TrackLoader = trackloader_scn.instantiate() + trackloader.track = t + %port.add_child(trackloader) + await RenderingServer.frame_post_draw + trackloader.queue_free() + var img: Image = %port.get_texture().get_image() + img.save_png(p) + (%thumb as TextureRect).texture = ImageTexture.create_from_image(img) + + + diff --git a/ui/tracks.gd b/ui/tracks.gd index 1b23df2..f2ea755 100644 --- a/ui/tracks.gd +++ b/ui/tracks.gd @@ -9,7 +9,7 @@ func _ready() -> void: var button := trackbutton.instantiate() add_child(button) var ghost := GhostData._load(Globals.SAVES % track.name) - button.init(ghost.time if ghost else -1, track.name) + await button.init(track, ghost) button.pressed.connect(track_selected.bind(track)) func track_selected(track: TrackResource) -> void: |