first save

This commit is contained in:
Crizomb 2025-08-02 19:37:16 +02:00
parent 814e50a862
commit ad95711535
14 changed files with 434 additions and 41 deletions

View file

@ -1,14 +0,0 @@
[gd_scene load_steps=3 format=3 uid="uid://cjk3phtyyiyty"]
[ext_resource type="Script" uid="uid://bdw7xdf1lc3ud" path="res://entities/do_spline.gd" id="1_c4y0q"]
[sub_resource type="Curve3D" id="Curve3D_p7e7j"]
_data = {
"points": PackedVector3Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.24595, 0, 10),
"tilts": PackedFloat32Array(0, 0)
}
point_count = 2
[node name="Track" type="Path3D"]
curve = SubResource("Curve3D_p7e7j")
script = ExtResource("1_c4y0q")

121
entities/car/car.gd Normal file
View file

@ -0,0 +1,121 @@
extends RigidBody3D
class_name Car
@export var forward_force: float = 100.0
@export var backward_force: float = 50.0
@export var steer_speed: float = 2.0
@export var base_lateral_friction: float = 5.0
@export var lateral_velocity_start_drift_threshold: float = 10.0
@export var lateral_velocity_total_drift_threshold: float = 15.0
@onready var forward_left: RayCast3D = $Raycasts/ForwardLeft
@onready var forward_right: RayCast3D = $Raycasts/ForwardRight
@onready var backward_right: RayCast3D = $Raycasts/BackwardRight
@onready var backward_left: RayCast3D = $Raycasts/BackwardLeft
@onready var forward_left_respawn: RayCast3D = $RaycastsRespawn/ForwardLeftRespawn
@onready var forward_right_respawn: RayCast3D = $RaycastsRespawn/ForwardRightRespawn
@onready var backward_right_respawn: RayCast3D = $RaycastsRespawn/BackwardRightRespawn
@onready var backward_left_respawn: RayCast3D = $RaycastsRespawn/BackwardLeftRespawn
var base_steer_speed: float
var current_steer_speed = base_steer_speed
var last_steer_input := 0.0
var rotation_angle := 0.0
var respawn_pos : Vector3
var thread: Thread = Thread.new()
var steer_input = 0.0
var cheat := false
var air_time := 0.0
func return_to_road():
position = respawn_pos + 3*Vector3.UP
rotation.z = 0
rotation.x = 0
linear_velocity = Vector3.ZERO
angular_velocity = Vector3.ZERO
air_time = 0.0
func _process(_delta: float) -> void:
if Input.is_action_just_pressed("restart"):
return_to_road()
func _physics_process(delta: float) -> void:
var move_input := Input.get_axis("back", "forward")
var steer_input_brut := Input.get_axis("right", "left")
steer_input = lerpf(steer_input, steer_input_brut, 0.1)
var is_on_floor := backward_left_respawn.is_colliding() || backward_right_respawn.is_colliding() || forward_left_respawn.is_colliding() || forward_right_respawn.is_colliding()
var is_all_wheel_on_floor := backward_left_respawn.is_colliding() && backward_right_respawn.is_colliding() && forward_left_respawn.is_colliding() && forward_right_respawn.is_colliding()
var is_flat : bool = transform.basis.y.dot(Vector3.UP) > 0.9
if is_all_wheel_on_floor && is_flat:
respawn_pos = position
if !is_on_floor && !cheat:
#$DriftParticles.emitting = false
#$DriftParticles2.emitting = false
#AudioServer.set_bus_volume_db(5, -80)
air_time += delta
if air_time > 1.5:
return_to_road()
return
air_time = 0.0
if cheat && Input.is_key_pressed(KEY_SPACE):
linear_velocity.y += 20*delta
if cheat:
forward_force = 500
# Movement
if move_input > 0.0:
apply_central_force(global_transform.basis.z * forward_force)
elif move_input < 0.0:
var break_or_backward = 2*backward_force if global_transform.basis.z.dot(linear_velocity) > 0 else backward_force
apply_central_force(global_transform.basis.z * -break_or_backward)
# Rotation
rotation_angle = steer_input * delta
#angular_velocity = steer_input * delta * global_transform.basis.y * 30.0
rotate(global_transform.basis.y, rotation_angle)
# Drift Simulation
var velocity = linear_velocity
var forward_dir = global_transform.basis.z
if forward_dir.length_squared() == 0.0:
return # skip drift this frame if something is invalid
forward_dir = forward_dir.normalized()
var forward_velocity = forward_dir * velocity.dot(forward_dir)
var lateral_velocity = velocity - forward_velocity
var drift_factor = inverse_lerp(
lateral_velocity_total_drift_threshold,
lateral_velocity_start_drift_threshold,
lateral_velocity.length()
)
drift_factor = clamp(drift_factor, 0, 1)
#$DriftParticles.emitting = drift_factor < 1 && is_on_floor
#$DriftParticles2.emitting = drift_factor < 1 && is_on_floor
#if drift_factor < 1 && is_on_floor:
#AudioServer.set_bus_volume_db(5, lerp(-15, -30, drift_factor))
#else:
#AudioServer.set_bus_volume_db(5, -80)
steer_speed = lerp(steer_speed * 2.0, base_steer_speed, drift_factor)
var lateral_friction_force = -lateral_velocity * base_lateral_friction * drift_factor
apply_central_force(lateral_friction_force)

1
entities/car/car.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://ctjy0e806j0vk

47
entities/car/car.tscn Normal file
View file

@ -0,0 +1,47 @@
[gd_scene load_steps=4 format=3 uid="uid://dgs0fqojgcmu3"]
[ext_resource type="Script" uid="uid://ctjy0e806j0vk" path="res://entities/car/car.gd" id="1_nh45c"]
[sub_resource type="BoxMesh" id="BoxMesh_kkl2f"]
size = Vector3(1, 1, 2)
[sub_resource type="BoxShape3D" id="BoxShape3D_76tdi"]
size = Vector3(1, 1, 2)
[node name="Car" type="RigidBody3D"]
script = ExtResource("1_nh45c")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("BoxMesh_kkl2f")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.00250244)
shape = SubResource("BoxShape3D_76tdi")
[node name="Raycasts" type="Node3D" parent="."]
[node name="ForwardLeft" type="RayCast3D" parent="Raycasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, -1)
[node name="ForwardRight" type="RayCast3D" parent="Raycasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 0, -1)
[node name="BackwardRight" type="RayCast3D" parent="Raycasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 0, 1)
[node name="BackwardLeft" type="RayCast3D" parent="Raycasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 1)
[node name="RaycastsRespawn" type="Node3D" parent="."]
[node name="ForwardLeftRespawn" type="RayCast3D" parent="RaycastsRespawn"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, -1)
[node name="ForwardRightRespawn" type="RayCast3D" parent="RaycastsRespawn"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 0, -1)
[node name="BackwardRightRespawn" type="RayCast3D" parent="RaycastsRespawn"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 0, 1)
[node name="BackwardLeftRespawn" type="RayCast3D" parent="RaycastsRespawn"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 1)

View file

@ -0,0 +1,4 @@
[gd_resource type="PhysicsMaterial" format=3 uid="uid://doaljsb6138cp"]
[resource]
friction = 0.1

View file

@ -1,26 +0,0 @@
@tool
extends Path3D
class_name RoadPath
@export_tool_button("update_control_points") var action = update_control_points
func update_control_points():
if curve.point_count < 2:
return
# Start point: out control based on next point
var dir = (curve.get_point_position(1) - curve.get_point_position(0)).normalized()
var tangent_length = dir.length() / 3
curve.set_point_out(0, dir * tangent_length)
# Intermediate points: in and out controls based on adjacent points
for i in range(1, curve.point_count - 1):
var prev_dir = (curve.get_point_position(i) - curve.get_point_position(i - 1)).normalized()
var next_dir = (curve.get_point_position(i + 1) - curve.get_point_position(i)).normalized()
tangent_length = next_dir.length() / 3
var tangent = (prev_dir + next_dir)
tangent.y = 0
tangent = tangent.normalized()
curve.set_point_in(i, -tangent * tangent_length)
curve.set_point_out(i, tangent * tangent_length)

View file

@ -0,0 +1,32 @@
@tool
extends Path3D
class_name RoadPath
@export_tool_button("update_control_points") var action = update_control_points
func modulo_get_point_position(i):
return curve.get_point_position(posmod(i, curve.point_count))
func update_control_points():
if curve.point_count < 2:
return
#
## Start point: out control based on next point
#var dir = (curve.get_point_position(1) - curve.get_point_position(0)).normalized()
#var tangent_length = dir.length() / 3
#
#curve.set_point_out(0, dir * tangent_length)
# Intermediate points: in and out controls based on adjacent points
for i in range(0, curve.point_count):
var prev = modulo_get_point_position(i) - modulo_get_point_position(i - 1)
var next = modulo_get_point_position(i + 1) - modulo_get_point_position(i)
var prev_dir = prev.normalized()
var next_dir = next.normalized()
var tangent_length = next.length() / 3
var tangent = (prev_dir + next_dir)
tangent.y = 0
tangent = tangent.normalized()
curve.set_point_in(i, -tangent * tangent_length)
curve.set_point_out(i, tangent * tangent_length)

118
entities/road/road.gd Normal file
View file

@ -0,0 +1,118 @@
@tool
extends StaticBody3D
class_name Road
@export_tool_button("create_mesh") var action_generate = generate_mesh
@export_tool_button("clear_all") var action_clear = clear_all
@export var track : RoadPath
@export var road_mesh_instance : MeshInstance3D
@export var road_shape : CollisionShape3D
@export var road_material : BaseMaterial3D
@export var segment_length := 0.1
@export var road_width : float = 1.5
@export var road_thickness : float = 0.5
var st_road = SurfaceTool.new()
func clear_all():
st_road = SurfaceTool.new()
st_road.clear()
road_mesh_instance.mesh = null
if road_shape and road_shape.shape:
road_shape.shape = null
func generate_mesh():
clear_all()
st_road.begin(Mesh.PRIMITIVE_TRIANGLES)
if road_material:
st_road.set_material(road_material)
var curve := track.curve
var race_length = curve.get_baked_length()
var nb_of_point : int = race_length / segment_length
for i in range(nb_of_point):
var dist1 = float(i) * segment_length
var dist2 = float(i + 1) * segment_length
var t1 := curve.sample_baked_with_rotation(dist1, true)
var t2 := curve.sample_baked_with_rotation(dist2, true)
var fwd1 = t1.basis.z.normalized()
var fwd2 = t2.basis.z.normalized()
var right1 = t1.basis.x.normalized()
var right2 = t2.basis.x.normalized()
var left1 = -right1
var left2 = -right2
var up1 = t1.basis.y.normalized()
var up2 = t2.basis.y.normalized()
var p1 := t1.origin
if i == 0:
p1 += fwd1 * 0.05
var p2 := t2.origin
# Top vertices
var p1_right = p1 + right1 * road_width * 0.5
var p1_left = p1 - right1 * road_width * 0.5
var p2_right = p2 + right2 * road_width * 0.5
var p2_left = p2 - right2 * road_width * 0.5
# Bottom vertices
var p1_right_bottom = p1_right - up1 * road_thickness
var p1_left_bottom = p1_left - up1 * road_thickness
var p2_right_bottom = p2_right - up2 * road_thickness
var p2_left_bottom = p2_left - up2 * road_thickness
# Top face
create_rectangle(p1_right, p1_left, p2_left, p2_right, up1, up2, Vector2(0, dist1 / road_width), Vector2(1, dist2 / road_width))
# Bottom face (inverted normal)
create_rectangle(p1_left_bottom, p1_right_bottom, p2_right_bottom, p2_left_bottom, up1, up2, Vector2(1, dist1 / road_width), Vector2(0, dist2 / road_width))
# Right side face
create_rectangle(p1_right_bottom, p1_right, p2_right, p2_right_bottom, right1, right2, Vector2(dist1 / road_thickness, 0), Vector2(dist2 / road_thickness, 1))
# Left side face
create_rectangle(p1_left, p1_left_bottom, p2_left_bottom, p2_left, left1, left2, Vector2(dist1 / road_thickness, 0), Vector2(dist2 / road_thickness, 1))
var final_mesh = st_road.commit()
road_mesh_instance.mesh = final_mesh
var shape = final_mesh.create_trimesh_shape()
road_shape.shape = shape
func create_rectangle(
v1: Vector3, v2: Vector3, v3: Vector3, v4: Vector3,
normal1: Vector3, normal2: Vector3,
uv1: Vector2, uv2: Vector2
):
# Triangle 1
st_road.set_uv(uv1)
st_road.set_normal(normal1)
st_road.add_vertex(v1)
st_road.set_uv(Vector2(uv1.x, uv2.y))
st_road.set_normal(normal1)
st_road.add_vertex(v2)
st_road.set_uv(uv2)
st_road.set_normal(normal2)
st_road.add_vertex(v3)
# Triangle 2
st_road.set_uv(uv2)
st_road.set_normal(normal2)
st_road.add_vertex(v3)
st_road.set_uv(Vector2(uv2.x, uv1.y))
st_road.set_normal(normal1)
st_road.add_vertex(v4)
st_road.set_uv(uv1)
st_road.set_normal(normal1)
st_road.add_vertex(v1)

View file

@ -0,0 +1 @@
uid://bgt66573ipmub

33
entities/road/road.tscn Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,16 @@
[gd_scene load_steps=3 format=3 uid="uid://cjk3phtyyiyty"]
[ext_resource type="Script" uid="uid://bdw7xdf1lc3ud" path="res://entities/road/do_spline.gd" id="1_c4y0q"]
[sub_resource type="Curve3D" id="Curve3D_p7e7j"]
closed = true
_data = {
"points": PackedVector3Array(0.246495, 0, 4.21189, -0.246495, 0, -4.21189, 0, 0, 0, -4.24042, 0, 0.00829778, 4.24042, 0, -0.00829778, 10, 0, -7.75931, -4.21783, 0, -0.014848, 4.21783, 0, 0.014848, 20, 1.27448, 0, -4.24638, 0, 0.0109491, 4.24638, 0, -0.0109491, 30, 0, -7.64779, -2.44782, 0, -6.85357, 2.44782, 0, 6.85357, 40, 1.9489, 0, 12.6025, 0, -5.29505, -12.6025, 0, 5.29505, 35.1108, 0, 21.1888),
"tilts": PackedFloat32Array(0, 0, 0, 0, 0, 0)
}
point_count = 6
[node name="Track" type="Path3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00397015, 0, 0)
curve = SubResource("Curve3D_p7e7j")
script = ExtResource("1_c4y0q")

View file

@ -11,9 +11,46 @@ config_version=5
[application] [application]
config/name="Looping" config/name="Looping"
run/main_scene="uid://bd8skoxlvujam"
config/features=PackedStringArray("4.4", "GL Compatibility") config/features=PackedStringArray("4.4", "GL Compatibility")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[input]
forward={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":122,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"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,"location":0,"echo":false,"script":null)
]
}
back={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"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,"location":0,"echo":false,"script":null)
]
}
right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
restart={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null)
]
}
[physics]
3d/physics_engine="Jolt Physics"
[rendering] [rendering]
renderer/rendering_method="gl_compatibility" renderer/rendering_method="gl_compatibility"

View file

@ -1,3 +1,26 @@
[gd_scene format=3 uid="uid://bd8skoxlvujam"] [gd_scene load_steps=5 format=3 uid="uid://bd8skoxlvujam"]
[ext_resource type="PackedScene" uid="uid://d5co10opkoxg" path="res://entities/road/road.tscn" id="1_o5qli"]
[ext_resource type="PackedScene" uid="uid://dgs0fqojgcmu3" path="res://entities/car/car.tscn" id="2_0wfyh"]
[ext_resource type="PhysicsMaterial" uid="uid://doaljsb6138cp" path="res://entities/car/car_physic_mat.tres" id="3_sugp2"]
[sub_resource type="Environment" id="Environment_0wfyh"]
[node name="Main" type="Node3D"] [node name="Main" type="Node3D"]
[node name="Road" parent="." instance=ExtResource("1_o5qli")]
road_width = 3.0
[node name="Car" parent="." instance=ExtResource("2_0wfyh")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0846112, 3.64068, -0.427136)
mass = 10.0
physics_material_override = ExtResource("3_sugp2")
[node name="Camera3D" type="Camera3D" parent="Car"]
transform = Transform3D(-0.995019, 0, -0.0996845, -0.0423712, 0.905169, 0.422936, 0.0902313, 0.425053, -0.90066, 0.00947832, 1.60507, -2.49832)
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_0wfyh")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.903903, -0.229357, 0.361046, 0, 0.844085, 0.53621, -0.427737, -0.484682, 0.762971, 0, 3.75849, 0)