small racing game im working on
Diffstat (limited to 'car.gd')
-rw-r--r--car.gd135
1 files changed, 66 insertions, 69 deletions
diff --git a/car.gd b/car.gd
index fe75277..87fbab7 100644
--- a/car.gd
+++ b/car.gd
@@ -1,83 +1,80 @@
-extends VehicleBody3D
+extends Node3D
class_name Car
-@export var STEER_SPEED := 0.1
-@export var MAX_ENGINE_FORCE := 700.0
-@export var MAX_BRAKE_FORCE := 50.0
+@onready var ball := $Ball as RigidBody3D
+@onready var car_mesh := $CarMesh as Node3D
+@onready var ground_ray := $CarMesh/GroundRay as RayCast3D
+# mesh references
+@onready var right_wheel := $CarMesh/frontright as MeshInstance3D
+@onready var left_wheel := $CarMesh/frontleft as MeshInstance3D
+@onready var skid_l = $CarMesh/SkidL as GPUParticles3D
+@onready var skid_r = $CarMesh/SkidR as GPUParticles3D
+@onready var body_mesh := $CarMesh/body as MeshInstance3D
+@export var show_debug := false
-@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 acceleration := 35.0 # ai must change this for randomness
+const sphere_offset := Vector3(0, -2, .5)
+const max_steering_range := deg_to_rad(40.0)
+const turn_speed := 2.0
+const wheel_turn_speed := 0.2
+const turn_stop_limit := 0.75
+const body_tilt := 685.0
-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
+var throttle := 0.0
+var _steering := 0.0
-func get_speed_kph():
- return current_speed_mps * 3600.0 / 1000.0
+func _ready():
+ $Ball/DebugMesh.visible = show_debug
+ ground_ray.add_exception(ball)
-# 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
+func steer(to: float) -> void:
+ _steering = clamp(lerpf(_steering, -to, wheel_turn_speed), -max_steering_range, max_steering_range)
+ if is_zero_approx(_steering) or (_steering < .05 && _steering > -.05):
+ _steering = 0
+ # rotate wheels for effect
+ right_wheel.rotation.y = _steering * .75
+ left_wheel.rotation.y = _steering * .75
- 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 move_mesh(delta: float) -> void:
+ # just lerp the y due to trimesh bouncing
+ car_mesh.transform.origin.x = ball.transform.origin.x + sphere_offset.x
+ car_mesh.transform.origin.z = ball.transform.origin.z + sphere_offset.z
+ car_mesh.transform.origin.y = lerp(car_mesh.transform.origin.y, ball.transform.origin.y + sphere_offset.y, 1 * delta)
+ ball.apply_central_force(-car_mesh.global_transform.basis.z * throttle)
-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 turn(delta: float) -> void:
+ if ball.linear_velocity.length() > turn_stop_limit:
+ var new_basis := car_mesh.global_transform.basis.rotated(car_mesh.global_transform.basis.y, _steering)
+ car_mesh.global_transform.basis = car_mesh.global_transform.basis.slerp(new_basis, turn_speed * delta)
+ car_mesh.global_transform = car_mesh.global_transform.orthonormalized()
+ # tilt body for effect
+ body_mesh.rotation.z = lerp(body_mesh.rotation.z, clampf((-_steering * .2) * ball.linear_velocity.length_squared() / body_tilt, -.4, .4), 10 * delta)
-func _process(delta: float):
- _process_gear_inputs(delta)
+func floor_mesh(delta: float) -> void:
+ var n = ground_ray.get_collision_normal()
+ var xform := align_with_y(car_mesh.global_transform, n.normalized())
+ car_mesh.global_transform = car_mesh.global_transform.interpolate_with(xform, 10 * 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")
+func _physics_process(delta: float) -> void:
+ move_mesh(delta)
- var power_factor = power_curve.sample_baked(clamp(calculate_rpm() / max_engine_rpm, 0.0, 1.0))
+ # if not ground_ray.is_colliding():
+ # return
- 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
+ # print(ball.linear_velocity.normalized().dot(-car_mesh.transform.basis.y))
+ # if throttle < 0 && :
+ # steering = -steering
- 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
+ # drift particles
+ var drift: bool = ball.linear_velocity.length() > 25 and abs(ball.linear_velocity.normalized().dot(-car_mesh.transform.basis.z)) > .5
+ skid_l.emitting = drift
+ skid_r.emitting = drift
- # remember where we are
- last_pos = position
+ turn(delta)
+ floor_mesh(delta)
+
+func align_with_y(xform: Transform3D, new_y: Vector3) -> Transform3D:
+ xform.basis.y = new_y
+ xform.basis.x = -xform.basis.z.cross(new_y)
+ xform.basis = xform.basis.orthonormalized()
+ return xform