small racing game im working on
saving scripts & such: switching to ball car
bendn 2023-01-25
commit 1a170e8
-rw-r--r--.gitignore3
-rw-r--r--.vscode/settings.json3
-rw-r--r--assets/cars/cruella/cruella.blendbin0 -> 1187736 bytes
-rw-r--r--assets/cars/cruella/cruella.blend.import46
-rw-r--r--assets/cars/cruella/cruella.tscn69
-rw-r--r--assets/cars/kenney_sedan/sedan.blendbin0 -> 1170792 bytes
-rw-r--r--assets/cars/kenney_sedan/sedan.blend.import46
-rw-r--r--assets/cars/kenney_sedan/sedan.tscn20
-rw-r--r--assets/floor.jpgbin0 -> 1203925 bytes
-rw-r--r--assets/floor.jpg.import36
-rw-r--r--assets/grass.pngbin0 -> 144 bytes
-rw-r--r--assets/grass.png.import36
-rw-r--r--assets/hdri.jpgbin0 -> 222180 bytes
-rw-r--r--assets/hdri.jpg.import36
-rw-r--r--assets/mats/grass.tres10
-rw-r--r--assets/mats/support.tres7
-rw-r--r--assets/road.pngbin0 -> 549 bytes
-rw-r--r--assets/road.png.import34
-rw-r--r--assets/sounds/brake.wavbin0 -> 160032 bytes
-rw-r--r--assets/sounds/brake.wav.import24
-rw-r--r--assets/sounds/shifts/1.wavbin0 -> 53678 bytes
-rw-r--r--assets/sounds/shifts/1.wav.import24
-rw-r--r--assets/sounds/shifts/2.wavbin0 -> 45228 bytes
-rw-r--r--assets/sounds/shifts/2.wav.import24
-rw-r--r--assets/sounds/shifts/3.wavbin0 -> 15206 bytes
-rw-r--r--assets/sounds/shifts/3.wav.import24
-rw-r--r--assets/support.pngbin0 -> 97 bytes
-rw-r--r--assets/support.png.import34
-rw-r--r--cam.gd30
-rw-r--r--cam.tres3
-rw-r--r--car.gd83
-rw-r--r--default_env.tres26
-rw-r--r--main.gd1
-rw-r--r--main.tscn120
-rw-r--r--project.godot76
-rw-r--r--rail.tres6
-rw-r--r--scenes/track-base.gd96
-rw-r--r--scenes/track.tscn87
-rw-r--r--test.gd6
-rw-r--r--track.gd12
-rw-r--r--tracks/speedway_curve.tres8
-rw-r--r--tracks/speedway_track.tres12
-rw-r--r--ui/boldsans.tres4
-rw-r--r--ui/gears.gd10
-rw-r--r--ui/panel_skewed.tres12
-rw-r--r--ui/revs.gd7
-rw-r--r--ui/speedometer.gd7
-rw-r--r--ui/theme.tres14
-rw-r--r--ui/ubuntu.tres4
49 files changed, 1100 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..67f574c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.godot/
+movie.*
+*.blend1
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..d773226
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "godot_tools.gdscript_lsp_server_port": 6005
+}
diff --git a/assets/cars/cruella/cruella.blend b/assets/cars/cruella/cruella.blend
new file mode 100644
index 0000000..19497b7
--- /dev/null
+++ b/assets/cars/cruella/cruella.blend
Binary files differ
diff --git a/assets/cars/cruella/cruella.blend.import b/assets/cars/cruella/cruella.blend.import
new file mode 100644
index 0000000..0da1947
--- /dev/null
+++ b/assets/cars/cruella/cruella.blend.import
@@ -0,0 +1,46 @@
+[remap]
+
+importer="scene"
+importer_version=1
+type="PackedScene"
+uid="uid://ci8a2pe7ux1ol"
+path="res://.godot/imported/cruella.blend-fb9d7f3600a3bed31701aa78016af2ed.scn"
+
+[deps]
+
+source_file="res://assets/cars/cruella/cruella.blend"
+dest_files=["res://.godot/imported/cruella.blend-fb9d7f3600a3bed31701aa78016af2ed.scn"]
+
+[params]
+
+nodes/root_type="VehicleBody3D"
+nodes/root_name="Cruella"
+nodes/apply_root_scale=true
+nodes/root_scale=1.0
+meshes/ensure_tangents=true
+meshes/generate_lods=true
+meshes/create_shadow_meshes=true
+meshes/light_baking=1
+meshes/lightmap_texel_size=0.2
+skins/use_named_skins=true
+animation/import=true
+animation/fps=30
+animation/trimming=false
+import_script/path=""
+_subresources={}
+blender/nodes/visible=1
+blender/nodes/punctual_lights=true
+blender/nodes/cameras=true
+blender/nodes/custom_properties=true
+blender/nodes/modifiers=1
+blender/meshes/colors=false
+blender/meshes/uvs=true
+blender/meshes/normals=true
+blender/meshes/tangents=true
+blender/meshes/skins=2
+blender/meshes/export_bones_deforming_mesh_only=false
+blender/materials/unpack_enabled=true
+blender/materials/export_materials=1
+blender/animation/limit_playback=true
+blender/animation/always_sample=true
+blender/animation/group_tracks=true
diff --git a/assets/cars/cruella/cruella.tscn b/assets/cars/cruella/cruella.tscn
new file mode 100644
index 0000000..dd108f6
--- /dev/null
+++ b/assets/cars/cruella/cruella.tscn
@@ -0,0 +1,69 @@
+[gd_scene load_steps=4 format=3 uid="uid://c4wei884eefjq"]
+
+[ext_resource type="PackedScene" uid="uid://ci8a2pe7ux1ol" path="res://assets/cars/cruella/cruella.blend" id="1_nkrbo"]
+[ext_resource type="Script" path="res://car.gd" id="2_rs08l"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_p6ojk"]
+size = Vector3(3, 1, 5.5)
+
+[node name="Cruella" instance=ExtResource("1_nkrbo")]
+mass = 300.0
+script = ExtResource("2_rs08l")
+MAX_ENGINE_FORCE = 600.0
+
+[node name="tr" parent="." index="8"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.2, -0.5, 2.241)
+use_as_steering = true
+wheel_rest_length = 0.2
+suspension_travel = 0.2
+suspension_stiffness = 200.0
+damping_compression = 0.7
+damping_relaxation = 0.8
+metadata/_edit_group_ = true
+
+[node name="wheel_control" parent="tr" index="0"]
+transform = Transform3D(9.55344e-16, -2.18557e-08, 0.5, -0.5, -2.18557e-08, 1.52201e-21, 2.18557e-08, -0.5, -2.18557e-08, 0, 0, 0)
+
+[node name="tl" parent="." index="9"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.2, -0.5, 2.24148)
+use_as_steering = true
+wheel_rest_length = 0.2
+suspension_travel = 0.2
+suspension_stiffness = 200.0
+damping_compression = 0.7
+damping_relaxation = 0.8
+metadata/_edit_group_ = true
+
+[node name="wheel_control2" parent="tl" index="0"]
+transform = Transform3D(1.96179e-15, 9.73536e-08, -0.5, -0.5, -2.18557e-08, -6.21725e-15, -2.18557e-08, 0.5, 9.73536e-08, 0, 0, 0)
+
+[node name="bl" parent="." index="10"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.2, -0.5, -1.74956)
+use_as_traction = true
+wheel_rest_length = 0.2
+suspension_travel = 0.2
+suspension_stiffness = 200.0
+suspension_max_force = 10000.0
+damping_compression = 0.7
+damping_relaxation = 0.8
+metadata/_edit_group_ = true
+
+[node name="wheel_control3" parent="bl" index="0"]
+transform = Transform3D(1.96179e-15, 9.73536e-08, -0.5, -0.5, -2.18557e-08, -6.21725e-15, -2.18557e-08, 0.5, 9.73536e-08, 0, 0, 0)
+
+[node name="br" parent="." index="11"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.2, -0.5, -1.75)
+use_as_traction = true
+wheel_rest_length = 0.2
+suspension_travel = 0.2
+suspension_stiffness = 200.0
+damping_compression = 0.7
+damping_relaxation = 0.8
+metadata/_edit_group_ = true
+
+[node name="wheel_control4" parent="br" index="0"]
+transform = Transform3D(9.55344e-16, -2.18557e-08, 0.5, -0.5, -2.18557e-08, 1.52201e-21, 2.18557e-08, -0.5, -2.18557e-08, 0, 0, 0)
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="." index="14"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1273, 0)
+shape = SubResource("BoxShape3D_p6ojk")
diff --git a/assets/cars/kenney_sedan/sedan.blend b/assets/cars/kenney_sedan/sedan.blend
new file mode 100644
index 0000000..09bd170
--- /dev/null
+++ 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
new file mode 100644
index 0000000..ca20324
--- /dev/null
+++ b/assets/cars/kenney_sedan/sedan.blend.import
@@ -0,0 +1,46 @@
+[remap]
+
+importer="scene"
+importer_version=1
+type="PackedScene"
+uid="uid://b6vxr0dxeev81"
+path="res://.godot/imported/sedan.blend-3ceae6cdea71e2b9a73446751f661182.scn"
+
+[deps]
+
+source_file="res://assets/cars/kenney_sedan/sedan.blend"
+dest_files=["res://.godot/imported/sedan.blend-3ceae6cdea71e2b9a73446751f661182.scn"]
+
+[params]
+
+nodes/root_type="RigidBody3D"
+nodes/root_name="SedanSports"
+nodes/apply_root_scale=true
+nodes/root_scale=1.0
+meshes/ensure_tangents=true
+meshes/generate_lods=true
+meshes/create_shadow_meshes=true
+meshes/light_baking=1
+meshes/lightmap_texel_size=0.2
+skins/use_named_skins=true
+animation/import=true
+animation/fps=30
+animation/trimming=false
+import_script/path=""
+_subresources={}
+blender/nodes/visible=0
+blender/nodes/punctual_lights=true
+blender/nodes/cameras=true
+blender/nodes/custom_properties=true
+blender/nodes/modifiers=1
+blender/meshes/colors=false
+blender/meshes/uvs=true
+blender/meshes/normals=true
+blender/meshes/tangents=true
+blender/meshes/skins=2
+blender/meshes/export_bones_deforming_mesh_only=false
+blender/materials/unpack_enabled=true
+blender/materials/export_materials=1
+blender/animation/limit_playback=true
+blender/animation/always_sample=true
+blender/animation/group_tracks=true
diff --git a/assets/cars/kenney_sedan/sedan.tscn b/assets/cars/kenney_sedan/sedan.tscn
new file mode 100644
index 0000000..3fd85e5
--- /dev/null
+++ b/assets/cars/kenney_sedan/sedan.tscn
@@ -0,0 +1,20 @@
+[gd_scene load_steps=5 format=3 uid="uid://u8g53husgywi"]
+
+[ext_resource type="PackedScene" uid="uid://b6vxr0dxeev81" path="res://assets/cars/kenney_sedan/sedan.blend" id="1_a083g"]
+[ext_resource type="Script" path="res://car.gd" id="1_hlt8r"]
+
+[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_1m0u8"]
+bounce = 0.1
+
+[sub_resource type="SphereShape3D" id="SphereShape3D_2sf22"]
+radius = 1.0
+
+[node name="Sedan" type="Node3D"]
+
+[node name="SedanSports" parent="." instance=ExtResource("1_a083g")]
+physics_material_override = SubResource("PhysicsMaterial_1m0u8")
+script = ExtResource("1_hlt8r")
+
+[node name="Ball" type="CollisionShape3D" parent="SedanSports"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.956712, 0)
+shape = SubResource("SphereShape3D_2sf22")
diff --git a/assets/floor.jpg b/assets/floor.jpg
new file mode 100644
index 0000000..34d7ba2
--- /dev/null
+++ b/assets/floor.jpg
Binary files differ
diff --git a/assets/floor.jpg.import b/assets/floor.jpg.import
new file mode 100644
index 0000000..2faf5ed
--- /dev/null
+++ b/assets/floor.jpg.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ds3iuic6htw6t"
+path.s3tc="res://.godot/imported/floor.jpg-be9fbb376417ad83ba8cf9d14ee16fef.s3tc.ctex"
+path.etc2="res://.godot/imported/floor.jpg-be9fbb376417ad83ba8cf9d14ee16fef.etc2.ctex"
+metadata={
+"imported_formats": ["s3tc", "etc2"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://assets/floor.jpg"
+dest_files=["res://.godot/imported/floor.jpg-be9fbb376417ad83ba8cf9d14ee16fef.s3tc.ctex", "res://.godot/imported/floor.jpg-be9fbb376417ad83ba8cf9d14ee16fef.etc2.ctex"]
+
+[params]
+
+compress/mode=2
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/assets/grass.png b/assets/grass.png
new file mode 100644
index 0000000..0e30119
--- /dev/null
+++ b/assets/grass.png
Binary files differ
diff --git a/assets/grass.png.import b/assets/grass.png.import
new file mode 100644
index 0000000..9526749
--- /dev/null
+++ b/assets/grass.png.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dyk71hogwv01g"
+path.s3tc="res://.godot/imported/grass.png-a207bda4a53e32c7645a41ec6d1c234e.s3tc.ctex"
+path.etc2="res://.godot/imported/grass.png-a207bda4a53e32c7645a41ec6d1c234e.etc2.ctex"
+metadata={
+"imported_formats": ["s3tc", "etc2"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://assets/grass.png"
+dest_files=["res://.godot/imported/grass.png-a207bda4a53e32c7645a41ec6d1c234e.s3tc.ctex", "res://.godot/imported/grass.png-a207bda4a53e32c7645a41ec6d1c234e.etc2.ctex"]
+
+[params]
+
+compress/mode=2
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/assets/hdri.jpg b/assets/hdri.jpg
new file mode 100644
index 0000000..c95a847
--- /dev/null
+++ b/assets/hdri.jpg
Binary files differ
diff --git a/assets/hdri.jpg.import b/assets/hdri.jpg.import
new file mode 100644
index 0000000..d7f8568
--- /dev/null
+++ b/assets/hdri.jpg.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://2hbptxuf0j7i"
+path.s3tc="res://.godot/imported/hdri.jpg-c23344c6b15f5fde29a5fcec99b742d6.s3tc.ctex"
+path.etc2="res://.godot/imported/hdri.jpg-c23344c6b15f5fde29a5fcec99b742d6.etc2.ctex"
+metadata={
+"imported_formats": ["s3tc", "etc2"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://assets/hdri.jpg"
+dest_files=["res://.godot/imported/hdri.jpg-c23344c6b15f5fde29a5fcec99b742d6.s3tc.ctex", "res://.godot/imported/hdri.jpg-c23344c6b15f5fde29a5fcec99b742d6.etc2.ctex"]
+
+[params]
+
+compress/mode=2
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/assets/mats/grass.tres b/assets/mats/grass.tres
new file mode 100644
index 0000000..7a401d8
--- /dev/null
+++ b/assets/mats/grass.tres
@@ -0,0 +1,10 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b3sesqrdyxv5t"]
+
+[ext_resource type="Texture2D" uid="uid://dyk71hogwv01g" path="res://assets/grass.png" id="1_2pspn"]
+
+[resource]
+albedo_texture = ExtResource("1_2pspn")
+emission = Color(0, 0.0745098, 0.219608, 1)
+emission_energy_multiplier = 16.0
+ao_light_affect = 0.33
+uv1_scale = Vector3(100, 100, 100)
diff --git a/assets/mats/support.tres b/assets/mats/support.tres
new file mode 100644
index 0000000..7321acb
--- /dev/null
+++ b/assets/mats/support.tres
@@ -0,0 +1,7 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dk84idq7ktc5m"]
+
+[ext_resource type="Texture2D" uid="uid://b1re5kwpgdg07" path="res://assets/support.png" id="1_0m2od"]
+
+[resource]
+albedo_texture = ExtResource("1_0m2od")
+uv1_scale = Vector3(0.2, 0.2, 0.2)
diff --git a/assets/road.png b/assets/road.png
new file mode 100644
index 0000000..72c4efd
--- /dev/null
+++ b/assets/road.png
Binary files differ
diff --git a/assets/road.png.import b/assets/road.png.import
new file mode 100644
index 0000000..0999524
--- /dev/null
+++ b/assets/road.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://2fjjxft1ip57"
+path="res://.godot/imported/road.png-72005ad96a94b3869b023c4f4a0b0b7d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/road.png"
+dest_files=["res://.godot/imported/road.png-72005ad96a94b3869b023c4f4a0b0b7d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/assets/sounds/brake.wav b/assets/sounds/brake.wav
new file mode 100644
index 0000000..632e3ab
--- /dev/null
+++ b/assets/sounds/brake.wav
Binary files differ
diff --git a/assets/sounds/brake.wav.import b/assets/sounds/brake.wav.import
new file mode 100644
index 0000000..7b2763a
--- /dev/null
+++ b/assets/sounds/brake.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://dl0pr1ybrb532"
+path="res://.godot/imported/brake.wav-1746993b4e219d1db73af1da951bc051.sample"
+
+[deps]
+
+source_file="res://assets/sounds/brake.wav"
+dest_files=["res://.godot/imported/brake.wav-1746993b4e219d1db73af1da951bc051.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/assets/sounds/shifts/1.wav b/assets/sounds/shifts/1.wav
new file mode 100644
index 0000000..8d026fc
--- /dev/null
+++ b/assets/sounds/shifts/1.wav
Binary files differ
diff --git a/assets/sounds/shifts/1.wav.import b/assets/sounds/shifts/1.wav.import
new file mode 100644
index 0000000..5a983b5
--- /dev/null
+++ b/assets/sounds/shifts/1.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://di8wcnme3mqbf"
+path="res://.godot/imported/1.wav-38f1b5e1992f840a56602f7d26b59602.sample"
+
+[deps]
+
+source_file="res://assets/sounds/shifts/1.wav"
+dest_files=["res://.godot/imported/1.wav-38f1b5e1992f840a56602f7d26b59602.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/assets/sounds/shifts/2.wav b/assets/sounds/shifts/2.wav
new file mode 100644
index 0000000..c92c017
--- /dev/null
+++ b/assets/sounds/shifts/2.wav
Binary files differ
diff --git a/assets/sounds/shifts/2.wav.import b/assets/sounds/shifts/2.wav.import
new file mode 100644
index 0000000..c4b8c9d
--- /dev/null
+++ b/assets/sounds/shifts/2.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://ccm2hf8l35pw"
+path="res://.godot/imported/2.wav-8c4b5319fec15e92c4b36b9654238ac2.sample"
+
+[deps]
+
+source_file="res://assets/sounds/shifts/2.wav"
+dest_files=["res://.godot/imported/2.wav-8c4b5319fec15e92c4b36b9654238ac2.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/assets/sounds/shifts/3.wav b/assets/sounds/shifts/3.wav
new file mode 100644
index 0000000..85ea721
--- /dev/null
+++ b/assets/sounds/shifts/3.wav
Binary files differ
diff --git a/assets/sounds/shifts/3.wav.import b/assets/sounds/shifts/3.wav.import
new file mode 100644
index 0000000..7656247
--- /dev/null
+++ b/assets/sounds/shifts/3.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://bwgafws3iutsu"
+path="res://.godot/imported/3.wav-87a55cdf551011319cb0051e2fcc560f.sample"
+
+[deps]
+
+source_file="res://assets/sounds/shifts/3.wav"
+dest_files=["res://.godot/imported/3.wav-87a55cdf551011319cb0051e2fcc560f.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/assets/support.png b/assets/support.png
new file mode 100644
index 0000000..cf69f27
--- /dev/null
+++ b/assets/support.png
Binary files differ
diff --git a/assets/support.png.import b/assets/support.png.import
new file mode 100644
index 0000000..139db7a
--- /dev/null
+++ b/assets/support.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b1re5kwpgdg07"
+path="res://.godot/imported/support.png-adceb39ae871c36bd567614b58e6ead8.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/support.png"
+dest_files=["res://.godot/imported/support.png-adceb39ae871c36bd567614b58e6ead8.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/cam.gd b/cam.gd
new file mode 100644
index 0000000..6840b56
--- /dev/null
+++ b/cam.gd
@@ -0,0 +1,30 @@
+extends Camera3D
+
+@export var follow_this: Node3D
+@export var target_distance = 3.0
+@export var target_height = 2.0
+
+var last_lookat
+
+func _ready():
+ last_lookat = follow_this.global_transform.origin
+
+func _physics_process(delta):
+ var delta_v = global_transform.origin - follow_this.global_transform.origin
+ var target_pos = global_transform.origin
+
+ # ignore y
+ delta_v.y = 0.0
+
+ if (delta_v.length() > target_distance):
+ delta_v = delta_v.normalized() * target_distance
+ delta_v.y = target_height
+ target_pos = follow_this.global_transform.origin + delta_v
+ else:
+ target_pos.y = follow_this.global_transform.origin.y + target_height
+
+ global_transform.origin = global_transform.origin.lerp(target_pos, delta * 20.0)
+
+ last_lookat = last_lookat.lerp(follow_this.global_transform.origin, delta * 20.0)
+
+ look_at(last_lookat, Vector3(0.0, 1.0, 0.0))
diff --git a/cam.tres b/cam.tres
new file mode 100644
index 0000000..c8bbd60
--- /dev/null
+++ b/cam.tres
@@ -0,0 +1,3 @@
+[gd_resource type="CameraAttributesPractical" format=3 uid="uid://nhsovwj5hjip"]
+
+[resource]
diff --git a/car.gd b/car.gd
new file mode 100644
index 0000000..fe75277
--- /dev/null
+++ b/car.gd
@@ -0,0 +1,83 @@
+extends VehicleBody3D
+class_name Car
+
+@export var STEER_SPEED := 0.1
+@export var MAX_ENGINE_FORCE := 700.0
+@export var MAX_BRAKE_FORCE := 50.0
+
+@export var gear_ratios: Array[float] # 6
+@export var reverse_ratio := -2.5
+@export var final_drive_ratio := 3.38
+@export var max_engine_rpm := 8000.0
+@export var gear_shift_time = 0.3
+@export var power_curve: Curve = null
+
+var current_gear = 0 # -1 reverse, 0 = neutral, 1 - 6 = gear 1 to 6.
+const names: Array[StringName] = ["neutral", "first", "second", "third", "fourth", "fifth", "sixth", "reverse"] # -1 = last
+var clutch_position: float = 1.0 # 0.0 = clutch engaged
+var current_speed_mps = 0.0 # meters
+@onready var last_pos = position
+@export var wheel_radius: float
+@onready var wheel_circumference: float = 2.0 * PI * wheel_radius
+var gear_timer = 0.0
+
+func get_speed_kph():
+ return current_speed_mps * 3600.0 / 1000.0
+
+# calculate the RPM of our engine based on the current velocity of our car
+func calculate_rpm() -> float:
+ # if we are in neutral, no rpm
+ if current_gear == 0:
+ return 0.0
+
+ var wheel_rotation_speed: float = 60.0 * current_speed_mps / wheel_circumference
+ var drive_shaft_rotation_speed: float = wheel_rotation_speed * final_drive_ratio
+ if current_gear == -1:
+ # we are in reverse
+ return drive_shaft_rotation_speed * -reverse_ratio
+ elif current_gear <= gear_ratios.size():
+ return drive_shaft_rotation_speed * gear_ratios[current_gear - 1]
+ return 0.0
+
+func _process_gear_inputs(delta: float):
+ if gear_timer > 0.0:
+ gear_timer = max(0.0, gear_timer - delta)
+ clutch_position = 0.0
+ else:
+ if Input.is_action_just_pressed("shift_down") and current_gear > -1:
+ current_gear = current_gear - 1
+ gear_timer = gear_shift_time
+ clutch_position = 0.0
+ elif Input.is_action_just_pressed("shift_up") and current_gear < gear_ratios.size():
+ current_gear = current_gear + 1
+ gear_timer = gear_shift_time
+ clutch_position = 0.0
+ else:
+ clutch_position = 1.0
+
+func _process(delta: float):
+ _process_gear_inputs(delta)
+
+func _physics_process(delta):
+ current_speed_mps = (position - last_pos).length() / delta
+ var steer_val = Input.get_axis("ui_left", "ui_right")
+ var throttle_val = Input.get_action_strength("accel")
+ var brake_val = Input.get_action_strength("brake")
+
+ var power_factor = power_curve.sample_baked(clamp(calculate_rpm() / max_engine_rpm, 0.0, 1.0))
+
+ if current_gear == -1:
+ engine_force = clutch_position * throttle_val * power_factor * reverse_ratio * final_drive_ratio * MAX_ENGINE_FORCE
+ elif current_gear > 0 and current_gear <= gear_ratios.size():
+ engine_force = clutch_position * throttle_val * power_factor * gear_ratios[current_gear - 1] * final_drive_ratio * MAX_ENGINE_FORCE
+ else:
+ engine_force = 0.0
+
+ brake = brake_val * MAX_BRAKE_FORCE
+ steering = clamp(lerpf(steering + -(steer_val * STEER_SPEED), 0, STEER_SPEED), -.8, .8)
+ print("%0.2f" % steering)
+ if is_zero_approx(steering) or (steering < .05 && steering > -.05):
+ steering = 0
+
+ # remember where we are
+ last_pos = position
diff --git a/default_env.tres b/default_env.tres
new file mode 100644
index 0000000..e456854
--- /dev/null
+++ b/default_env.tres
@@ -0,0 +1,26 @@
+[gd_resource type="Environment" load_steps=5 format=3 uid="uid://biwshm46yl62v"]
+
+[sub_resource type="Gradient" id="Gradient_dslwg"]
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_gewg2"]
+gradient = SubResource("Gradient_dslwg")
+
+[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_57jkl"]
+sky_top_color = Color(0.282353, 0.372549, 1, 1)
+sky_horizon_color = Color(0.427451, 0.658824, 1, 1)
+sky_curve = 0.204906
+ground_bottom_color = Color(0.427451, 0.658824, 1, 1)
+ground_horizon_color = Color(0.427451, 0.658824, 1, 1)
+ground_curve = 13.0515
+
+[sub_resource type="Sky" id="Sky_c7ivh"]
+sky_material = SubResource("ProceduralSkyMaterial_57jkl")
+process_mode = 1
+
+[resource]
+background_mode = 2
+sky = SubResource("Sky_c7ivh")
+ambient_light_source = 3
+ambient_light_color = Color(0.87451, 0.87451, 0.815686, 1)
+volumetric_fog_density = 1.0
+adjustment_color_correction = SubResource("GradientTexture1D_gewg2")
diff --git a/main.gd b/main.gd
new file mode 100644
index 0000000..67e954f
--- /dev/null
+++ b/main.gd
@@ -0,0 +1 @@
+extends Node3D
diff --git a/main.tscn b/main.tscn
new file mode 100644
index 0000000..6b4e788
--- /dev/null
+++ b/main.tscn
@@ -0,0 +1,120 @@
+[gd_scene load_steps=17 format=3 uid="uid://bnbab2hgqh4w5"]
+
+[ext_resource type="Script" path="res://main.gd" id="1_cps4g"]
+[ext_resource type="Environment" uid="uid://biwshm46yl62v" path="res://default_env.tres" id="1_rbfsw"]
+[ext_resource type="CameraAttributesPractical" uid="uid://nhsovwj5hjip" path="res://cam.tres" id="2_rymfk"]
+[ext_resource type="Material" uid="uid://b3sesqrdyxv5t" path="res://assets/mats/grass.tres" id="3_iiti7"]
+[ext_resource type="Script" path="res://cam.gd" id="4_u07o8"]
+[ext_resource type="PackedScene" uid="uid://duba8yjseopy6" path="res://scenes/track.tscn" id="6_u5ece"]
+[ext_resource type="Theme" uid="uid://ch2uo5qd8ubx6" path="res://ui/theme.tres" id="8_qjj2f"]
+[ext_resource type="Script" path="res://ui/revs.gd" id="9_hvuf0"]
+[ext_resource type="Script" path="res://ui/speedometer.gd" id="10_fu5aw"]
+[ext_resource type="Script" path="res://ui/gears.gd" id="10_gvf44"]
+[ext_resource type="Curve3D" uid="uid://u2f56xx8h2re" path="res://tracks/speedway_curve.tres" id="12_5lojs"]
+[ext_resource type="Resource" uid="uid://d3te55uy5ei7k" path="res://tracks/speedway_track.tres" id="13_pjowj"]
+[ext_resource type="Script" path="res://test.gd" id="14_6hrhe"]
+
+[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_tkhh8"]
+
+[sub_resource type="PlaneMesh" id="PlaneMesh_ta0cd"]
+material = ExtResource("3_iiti7")
+size = Vector2(5000, 5000)
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_h85yi"]
+
+[node name="main" type="Node3D"]
+script = ExtResource("1_cps4g")
+
+[node name="Sun" type="DirectionalLight3D" parent="."]
+transform = Transform3D(0.261981, -0.791013, -0.55287, 0.791617, -0.15154, 0.591927, -0.552004, -0.592735, 0.586479, 0, 37.0187, 0)
+
+[node name="Env" type="WorldEnvironment" parent="."]
+environment = ExtResource("1_rbfsw")
+camera_attributes = ExtResource("2_rymfk")
+
+[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="Camera3D" type="Camera3D" parent="." node_paths=PackedStringArray("follow_this")]
+transform = Transform3D(-0.718418, -0.318909, -0.618201, 0.111279, -0.92996, 0.350416, -0.686653, 0.182953, 0.703588, -7.07504, 13.1712, 16.3801)
+script = ExtResource("4_u07o8")
+follow_this = NodePath("../Car/SedanSports")
+target_distance = 7.0
+target_height = 5.0
+
+[node name="Car" type="Node3D" parent="."]
+
+[node name="CanvasLayer" type="CanvasLayer" parent="."]
+
+[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer"]
+anchors_preset = 7
+anchor_left = 0.5
+anchor_top = 1.0
+anchor_right = 0.5
+anchor_bottom = 1.0
+offset_left = -152.0
+offset_top = -105.0
+offset_right = 152.0
+grow_horizontal = 2
+grow_vertical = 0
+theme = ExtResource("8_qjj2f")
+theme_override_constants/separation = 50
+
+[node name="Panel3" type="PanelContainer" parent="CanvasLayer/HBoxContainer"]
+layout_mode = 2
+theme = ExtResource("8_qjj2f")
+
+[node name="Revometer" type="Label" parent="CanvasLayer/HBoxContainer/Panel3" node_paths=PackedStringArray("car")]
+custom_minimum_size = Vector2(0, 105)
+layout_mode = 2
+size_flags_horizontal = 4
+text = " 0rpm"
+horizontal_alignment = 1
+vertical_alignment = 1
+script = ExtResource("9_hvuf0")
+car = NodePath("../../../../Car/SedanSports")
+
+[node name="Panel" type="PanelContainer" parent="CanvasLayer/HBoxContainer"]
+layout_mode = 2
+theme = ExtResource("8_qjj2f")
+
+[node name="Speedometer" type="Label" parent="CanvasLayer/HBoxContainer/Panel" node_paths=PackedStringArray("car")]
+custom_minimum_size = Vector2(0, 105)
+layout_mode = 2
+size_flags_horizontal = 4
+text = "龍 0km/h"
+horizontal_alignment = 1
+vertical_alignment = 1
+script = ExtResource("10_fu5aw")
+car = NodePath("../../../../Car/SedanSports")
+
+[node name="Panel2" type="PanelContainer" parent="CanvasLayer/HBoxContainer"]
+layout_mode = 2
+theme = ExtResource("8_qjj2f")
+
+[node name="Gearometer" type="RichTextLabel" parent="CanvasLayer/HBoxContainer/Panel2" node_paths=PackedStringArray("car")]
+custom_minimum_size = Vector2(244, 0)
+layout_mode = 2
+bbcode_enabled = true
+text = "[center] [b][color=#4682b4]N[/color][/b][/center]"
+fit_content_height = true
+scroll_active = false
+script = ExtResource("10_gvf44")
+car = NodePath("../../../../Car/SedanSports")
+
+[node name="Track" parent="." instance=ExtResource("6_u5ece")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
+curve = ExtResource("12_5lojs")
+track = ExtResource("13_pjowj")
+
+[node name="CSGBox3D" type="CSGBox3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.43223, 0)
+material = SubResource("StandardMaterial3D_h85yi")
+script = ExtResource("14_6hrhe")
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..ecc0948
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,76 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="tracer"
+run/main_scene="res://main.tscn"
+config/features=PackedStringArray("4.0")
+
+[display]
+
+window/size/viewport_width=1920
+window/size/viewport_height=1080
+window/stretch/mode="viewport"
+window/stretch/aspect="expand"
+
+[editor]
+
+movie_writer/movie_file="/home/bendn/Documents/tracer/movie.mp4.avi"
+movie_writer/disable_vsync=true
+movie_writer/fps=30
+
+[input]
+
+ui_left={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":4194319,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
+]
+}
+ui_right={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":4194321,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
+]
+}
+accel={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":5,"axis_value":1.0,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+brake={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":4,"axis_value":1.0,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+shift_up={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":90,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+shift_down={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":88,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+
+[physics]
+
+3d/default_gravity=15.0
+
+[rendering]
+
+renderer/rendering_method="gl_compatibility"
+textures/canvas_textures/default_texture_filter=0
diff --git a/rail.tres b/rail.tres
new file mode 100644
index 0000000..806a84e
--- /dev/null
+++ b/rail.tres
@@ -0,0 +1,6 @@
+[gd_resource type="StandardMaterial3D" format=3 uid="uid://dtpgjplswm6lr"]
+
+[resource]
+albedo_color = Color(0.6, 0.6, 0.6, 1)
+metallic = 0.83
+roughness = 0.22
diff --git a/scenes/track-base.gd b/scenes/track-base.gd
new file mode 100644
index 0000000..68ee5c6
--- /dev/null
+++ b/scenes/track-base.gd
@@ -0,0 +1,96 @@
+@tool
+extends Path3D
+
+@export var track: TrackResource = null:
+ set(new_track):
+ if track != new_track:
+ track = new_track
+ is_dirty = true
+ call_deferred("_update")
+@export var force_update: bool = false:
+ set(update):
+ if update == true && update != force_update:
+ force_update = false
+ is_dirty = true
+ call_deferred("_update")
+
+@onready var road := $Road as CSGPolygon3D
+@onready var support := $Support as CSGPolygon3D
+@onready var rail_l := $"Rail-L" as CSGPolygon3D
+@onready var rail_r := $"Rail-R" as CSGPolygon3D
+@onready var collision := $CollisionShape as CSGPolygon3D
+
+var is_dirty = true
+
+func vec(x := 0.0, y := 0.0) -> Vector2:
+ return Vector2(x, y)
+
+
+func _update():
+ if !is_dirty or !track or !track.track:
+ # curve = null
+ return
+ curve = track.track
+ curve.set_point_tilt(0, PI/2)
+ curve.set_point_tilt(curve.get_point_count() - 1, 0.0)
+
+ # update our track
+ var thw = track.track_width * 0.5 # track half width
+ road.polygon = PackedVector2Array([vec(-thw), vec(-thw, -0.1), vec(thw, -0.1), vec(thw)])
+ support.polygon = PackedVector2Array([
+ vec(-thw - 2.0, -0.17),
+ vec( thw + 2.0, -0.17),
+ vec( track.lower_support_width + 0.1, -track.support_height),
+ vec(-track.lower_support_width, -track.support_height)
+ ])
+
+ # update our rails
+
+ var rp := thw + track.rail_distance # rail position
+ rail_l.polygon = PackedVector2Array([
+ vec(rp, 0.5),
+ vec(rp - 0.05, 0.47),
+ vec(rp - 0.05, 0.43),
+ vec(rp, 0.4),
+ vec(rp, 0.55),
+ vec(rp - 0.05, 0.32),
+ vec(rp - 0.05, 0.28),
+ vec(rp, 0.25),
+ vec(rp + 0.05, 0.25),
+ vec(rp + 0.05, 0.5)
+ ])
+ rail_r.polygon = PackedVector2Array([
+ vec(-rp, 0.5),
+ vec(-rp + 0.05, 0.47),
+ vec(-rp + 0.05, 0.43),
+ vec(-rp, 0.4),
+ vec(-rp, 0.55),
+ vec(-rp + 0.05, 0.32),
+ vec(-rp + 0.05, 0.28),
+ vec(-rp, 0.25),
+ vec(-rp - 0.05, 0.25),
+ vec(-rp - 0.05, .5)
+ ])
+
+ # update our collision
+
+ var c = collision.polygon
+ c.set(0, Vector2(-rp, 0.0))
+ c.set(1, Vector2( rp, 0.0))
+ c.set(2, Vector2( rp, 5.0))
+ c.set(3, Vector2( rp + 3.0, 5.0))
+ c.set(4, Vector2( rp + 3.0, -1.0))
+ c.set(5, Vector2(-rp - 3.0, -1.0))
+ c.set(6, Vector2(-rp - 3.0, 5.0))
+ c.set(7, Vector2(-rp, 5.0))
+ collision.polygon = c
+
+ is_dirty = false
+
+func _ready():
+ call_deferred("_update")
+
+
+func _on_curve_changed() -> void:
+ is_dirty = true
+ call_deferred("_update")
diff --git a/scenes/track.tscn b/scenes/track.tscn
new file mode 100644
index 0000000..5f07f9e
--- /dev/null
+++ b/scenes/track.tscn
@@ -0,0 +1,87 @@
+[gd_scene load_steps=6 format=3 uid="uid://duba8yjseopy6"]
+
+[ext_resource type="Script" path="res://scenes/track-base.gd" id="1_ke7nx"]
+[ext_resource type="Texture2D" uid="uid://2fjjxft1ip57" path="res://assets/road.png" id="1_q0215"]
+[ext_resource type="Material" uid="uid://dtpgjplswm6lr" path="res://rail.tres" id="2_3pcob"]
+[ext_resource type="Material" uid="uid://dk84idq7ktc5m" path="res://assets/mats/support.tres" id="3_4570s"]
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xw8xl"]
+albedo_texture = ExtResource("1_q0215")
+uv1_scale = Vector3(8, 8, 8)
+
+[node name="TrackLoader" type="Path3D"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.70198, -8.01861, -4.84379)
+script = ExtResource("1_ke7nx")
+
+[node name="Road" type="CSGPolygon3D" parent="."]
+polygon = PackedVector2Array(-8.5, 0, -8.5, -0.1, 8.5, -0.1, 8.5, 0)
+mode = 2
+path_node = NodePath("..")
+path_interval_type = 0
+path_interval = 1.0
+path_simplify_angle = 2.0
+path_rotation = 2
+path_local = false
+path_continuous_u = true
+path_u_distance = 0.0
+path_joined = true
+material = SubResource("StandardMaterial3D_xw8xl")
+
+[node name="CollisionShape" type="CSGPolygon3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.165113, 0)
+visible = false
+use_collision = true
+polygon = PackedVector2Array(-11.5, 0, 11.5, 0, 11.5, 5, 14.5, 5, 14.5, -1, -14.5, -1, -14.5, 5, -11.5, 5)
+mode = 2
+path_node = NodePath("..")
+path_interval_type = 0
+path_interval = 1.0
+path_simplify_angle = 6.0
+path_rotation = 2
+path_local = false
+path_continuous_u = true
+path_u_distance = 1.0
+path_joined = true
+
+[node name="Rail-L" type="CSGPolygon3D" parent="."]
+polygon = PackedVector2Array(11.5, 0.5, 11.45, 0.47, 11.45, 0.43, 11.5, 0.4, 11.5, 0.55, 11.45, 0.32, 11.45, 0.28, 11.5, 0.25, 11.55, 0.25, 11.55, 0.5)
+mode = 2
+path_node = NodePath("..")
+path_interval_type = 0
+path_interval = 1.0
+path_simplify_angle = 2.0
+path_rotation = 2
+path_local = false
+path_continuous_u = true
+path_u_distance = 1.0
+path_joined = true
+material = ExtResource("2_3pcob")
+
+[node name="Rail-R" type="CSGPolygon3D" parent="."]
+polygon = PackedVector2Array(-11.5, 0.5, -11.45, 0.47, -11.45, 0.43, -11.5, 0.4, -11.5, 0.55, -11.45, 0.32, -11.45, 0.28, -11.5, 0.25, -11.55, 0.25, -11.55, 0.5)
+mode = 2
+path_node = NodePath("..")
+path_interval_type = 0
+path_interval = 1.0
+path_simplify_angle = 2.0
+path_rotation = 2
+path_local = false
+path_continuous_u = true
+path_u_distance = 1.0
+path_joined = true
+
+[node name="Support" type="CSGPolygon3D" parent="."]
+polygon = PackedVector2Array(-10.5, -0.17, 10.5, -0.17, 15.1, -8, -15, -8)
+mode = 2
+path_node = NodePath("..")
+path_interval_type = 0
+path_interval = 1.0
+path_simplify_angle = 5.0
+path_rotation = 2
+path_local = false
+path_continuous_u = true
+path_u_distance = 1.0
+path_joined = true
+material = ExtResource("3_4570s")
+
+[connection signal="curve_changed" from="." to="." method="_on_curve_changed"]
diff --git a/test.gd b/test.gd
new file mode 100644
index 0000000..7091872
--- /dev/null
+++ b/test.gd
@@ -0,0 +1,6 @@
+extends CSGBox3D
+
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ (material as StandardMaterial3D).msdf_outline_size = 50 \ No newline at end of file
diff --git a/track.gd b/track.gd
new file mode 100644
index 0000000..c29ab62
--- /dev/null
+++ b/track.gd
@@ -0,0 +1,12 @@
+extends Resource
+class_name TrackResource
+## Width of road
+@export var track_width = 17.0
+## Distance between rails and road
+@export var rail_distance = 3.0
+## Support base width
+@export var lower_support_width = 15.0
+## Height of supports
+@export var support_height = 8.0
+## Track curve
+@export var track: Curve3D = null \ No newline at end of file
diff --git a/tracks/speedway_curve.tres b/tracks/speedway_curve.tres
new file mode 100644
index 0000000..59a6b77
--- /dev/null
+++ b/tracks/speedway_curve.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Curve3D" format=3 uid="uid://u2f56xx8h2re"]
+
+[resource]
+_data = {
+"points": PackedVector3Array(0, 0, 0, -65, 0, 0, -65, 0, 65, -65, 0, 0, -65, 0, 0, -65, 0, -65, 0, 0, 0, 65, 0, 0, 65, 0, -65, 70, 0, 0, 0, 0, 0, 65, 0, 65, 70, 0, 0, 0, 0, 0, -65, 0, 65),
+"tilts": PackedFloat32Array(1.5708, 0, 0, 0, 0)
+}
+point_count = 5
diff --git a/tracks/speedway_track.tres b/tracks/speedway_track.tres
new file mode 100644
index 0000000..9bf6468
--- /dev/null
+++ b/tracks/speedway_track.tres
@@ -0,0 +1,12 @@
+[gd_resource type="Resource" script_class="TrackResource" load_steps=3 format=3 uid="uid://d3te55uy5ei7k"]
+
+[ext_resource type="Script" path="res://track.gd" id="1_c5h3o"]
+[ext_resource type="Curve3D" uid="uid://u2f56xx8h2re" path="res://tracks/speedway_curve.tres" id="2_33qpi"]
+
+[resource]
+script = ExtResource("1_c5h3o")
+track_width = 25.0
+rail_distance = 3.0
+lower_support_width = 18.0
+support_height = 2.0
+track = ExtResource("2_33qpi")
diff --git a/ui/boldsans.tres b/ui/boldsans.tres
new file mode 100644
index 0000000..c8d6596
--- /dev/null
+++ b/ui/boldsans.tres
@@ -0,0 +1,4 @@
+[gd_resource type="FontVariation" format=3 uid="uid://ba8ab6dti2fvo"]
+
+[resource]
+variation_embolden = 1.5
diff --git a/ui/gears.gd b/ui/gears.gd
new file mode 100644
index 0000000..54ba49a
--- /dev/null
+++ b/ui/gears.gd
@@ -0,0 +1,10 @@
+extends RichTextLabel
+
+@export var car: Node3D
+
+# assumes 6 gear + rev
+const F_STRING = "[center] [b]%s[/b][/center]"
+const GEARS: PackedStringArray = ["[color=#4682b4]N[/color]", "1", "2", "3", "4", "5", "6", "[color=#d84341]R[/color]"]
+
+func _process(_delta: float) -> void:
+ text = F_STRING % GEARS[car.current_gear]
diff --git a/ui/panel_skewed.tres b/ui/panel_skewed.tres
new file mode 100644
index 0000000..fdc8ad2
--- /dev/null
+++ b/ui/panel_skewed.tres
@@ -0,0 +1,12 @@
+[gd_resource type="StyleBoxFlat" format=3 uid="uid://cdth5nc7lbx1v"]
+
+[resource]
+content_margin_left = 10.0
+content_margin_right = 10.0
+bg_color = Color(0.133333, 0.133333, 0.133333, 0.635294)
+skew = Vector2(0.3, 0)
+corner_radius_top_left = 20
+corner_radius_top_right = 20
+corner_radius_bottom_right = 20
+corner_radius_bottom_left = 20
+corner_detail = 12
diff --git a/ui/revs.gd b/ui/revs.gd
new file mode 100644
index 0000000..deb2188
--- /dev/null
+++ b/ui/revs.gd
@@ -0,0 +1,7 @@
+extends Label
+
+@export var f_string = " %drpm"
+@export var car: Node3D
+
+func _process(_delta: float) -> void:
+ text = f_string % car.calculate_rpm()
diff --git a/ui/speedometer.gd b/ui/speedometer.gd
new file mode 100644
index 0000000..b58f195
--- /dev/null
+++ b/ui/speedometer.gd
@@ -0,0 +1,7 @@
+extends Label
+
+@export var f_string = "龍 %dkm/h"
+@export var car: Node3D
+
+func _process(_delta: float) -> void:
+ text = f_string % car.get_speed_kph()
diff --git a/ui/theme.tres b/ui/theme.tres
new file mode 100644
index 0000000..edf3250
--- /dev/null
+++ b/ui/theme.tres
@@ -0,0 +1,14 @@
+[gd_resource type="Theme" load_steps=4 format=3 uid="uid://ch2uo5qd8ubx6"]
+
+[ext_resource type="SystemFont" uid="uid://xriuk0v4f6wj" path="res://ui/ubuntu.tres" id="1_37cf0"]
+[ext_resource type="StyleBox" uid="uid://cdth5nc7lbx1v" path="res://ui/panel_skewed.tres" id="1_g8q83"]
+[ext_resource type="FontVariation" uid="uid://ba8ab6dti2fvo" path="res://ui/boldsans.tres" id="3_fpgf0"]
+
+[resource]
+Label/font_sizes/font_size = 76
+Label/fonts/font = ExtResource("1_37cf0")
+PanelContainer/styles/panel = ExtResource("1_g8q83")
+RichTextLabel/font_sizes/bold_font_size = 76
+RichTextLabel/font_sizes/normal_font_size = 76
+RichTextLabel/fonts/bold_font = ExtResource("3_fpgf0")
+RichTextLabel/fonts/normal_font = ExtResource("1_37cf0")
diff --git a/ui/ubuntu.tres b/ui/ubuntu.tres
new file mode 100644
index 0000000..99b8a80
--- /dev/null
+++ b/ui/ubuntu.tres
@@ -0,0 +1,4 @@
+[gd_resource type="SystemFont" format=3 uid="uid://xriuk0v4f6wj"]
+
+[resource]
+font_names = PackedStringArray("UbuntuMono Nerd Font")