Added Ackerman Steering

This commit is contained in:
Wheelbarrow
2025-07-21 21:26:14 -04:00
parent 75ae5521fd
commit 896996dac6
5 changed files with 67 additions and 9 deletions

41
car.gd
View File

@@ -1,12 +1,49 @@
class_name Car class_name Car
extends RigidBody3D extends RigidBody3D
@export var wheels: Array[Wheel] @export_group("Steering")
## Maximum angle of imaginary wheel at center front of the car
@export var max_steer_angle: float = 30
@export var steer_speed: float = 120
func _physics_process(_delta: float) -> void: @export_group("Wheels")
@export var front_right: Wheel
@export var front_left: Wheel
@export var back_right: Wheel
@export var back_left: Wheel
@onready var wheels: Array[Wheel] = [front_right, front_left, back_right, back_left]
#kinda cheeks but ignorable
@onready var wheelbase: float = front_right.position.distance_to(back_right.position)
@onready var track: float = front_right.position.distance_to(front_left.position)
var current_steer_angle: float = 0
func _physics_process(delta: float) -> void:
steer(delta)
for wheel: Wheel in wheels: for wheel: Wheel in wheels:
wheel.apply_forces(self) wheel.apply_forces(self)
func steer(delta: float) -> void:
var steer_input = Input.get_axis("Steer Right", "Steer Left")
if steer_input != 0:
current_steer_angle += steer_input * steer_speed * delta
current_steer_angle = clampf(current_steer_angle, -max_steer_angle, max_steer_angle)
else:
current_steer_angle = move_toward(current_steer_angle, 0, steer_speed * delta)
var current_steer_angle_rads: float = abs(deg_to_rad(current_steer_angle))
var numerator: float = 2 * wheelbase * sin(current_steer_angle_rads)
var steer_radius: float = 2 * wheelbase * cos(current_steer_angle_rads)
var inner_angle: float = atan(numerator / (steer_radius - track * sin(current_steer_angle_rads)))
var outer_angle: float = atan(numerator / (steer_radius + track * sin(current_steer_angle_rads)))
if 0 < current_steer_angle:
front_right.rotation.y = inner_angle
front_left.rotation.y = outer_angle
else:
front_right.rotation.y = -inner_angle
front_left.rotation.y = -outer_angle
##Point argument is in local space ##Point argument is in local space
func get_velocity_at_point(point: Vector3) -> Vector3: func get_velocity_at_point(point: Vector3) -> Vector3:
return linear_velocity + angular_velocity.cross(point - center_of_mass) return linear_velocity + angular_velocity.cross(point - center_of_mass)

View File

@@ -7,10 +7,13 @@
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_7822p"] [sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_7822p"]
points = PackedVector3Array(2.639865, -0.93180054, 2.1575794, 2.5861135, 1.1470379, -1.4858942, 2.3804116, 0.5341828, 5.2797356, 2.3804116, 0.18806255, 5.32922, 2.3804116, -0.8661753, 4.864291, 2.3804116, -1.0148906, 4.0564213, 2.6011019, -0.9791671, 0.85025597, 2.590765, -0.8667045, -2.7230182, 2.590765, -0.28533888, -2.7966702, 1.4661236, 1.6421381, -0.30746174, 1.4661236, 1.6421381, 1.965394, 2.2072706, 0.77604365, 5.2682266, 2.4093547, -0.27607727, -5.989025, 2.3804116, 0.40134466, -4.392848, 2.2186413, 0.11079419, -5.824459, 1.82481, 0.6985105, -5.445842, 2.3230424, -0.08025998, 5.6525984, 2.212439, -0.45231283, 5.6169233, 0.3802452, -0.5354029, 5.61232, -2.3812249, -0.8661753, 4.864291, -2.3812249, -1.0148906, 4.0564213, 2.3804116, -1.0148906, -4.7944813, 2.3804116, -0.9804902, -5.7243385, 0.8805454, 1.6670123, -0.30746174, 1.7379808, 0.72020924, -5.445842, 1.0908988, 0.8818908, -5.445842, 0.8805454, 1.6670123, 1.965394, 0.9823625, 1.0935851, 5.340728, 1.5581212, 1.056274, 5.295847, 2.2506852, -0.2766065, -5.998232, 1.3152068, -0.28031117, -6.0511694, 0.3802452, -0.28401583, -6.102956, 0.3802452, -0.05273974, 5.649146, -2.310418, -0.08025998, 5.6537495, -0.38105845, -0.5354029, 5.61232, -2.1574335, -0.42452794, 5.6169233, -2.3812249, 0.18806255, 5.32922, -2.640161, -0.93180054, 2.1575794, -2.601915, -0.9791671, 0.85025597, -2.3812249, -1.0148906, -4.7944813, -2.3812249, -0.9804902, -5.7243385, 0.3802452, -0.4711007, -6.001684, 0.3802452, 1.6881818, -0.30746174, -1.0917118, 0.8818908, -5.445842, -0.38105845, 1.6884462, -0.30746174, 0.3802452, 1.6881818, 1.965394, -0.98317564, 1.0935851, 5.340728, -0.38105845, 1.6884462, 1.965394, -0.38105845, -0.28401583, -6.102956, -0.38105845, -0.05273974, 5.649146, -2.3812249, 0.5341828, 5.2797356, -2.3812249, 0.4148401, 5.296997, -1.559451, 1.056274, 5.295847, -2.2086005, 0.77604365, 5.2682266, -2.5869267, 1.1470379, -1.4858942, -2.5920951, -0.28533888, -2.7966702, -2.5920951, -0.8667045, -2.7230182, -2.415853, -0.28401583, -6.0488677, -2.390011, -0.7981685, -5.8094983, -1.3129189, -0.28401583, -6.0787888, -0.38105845, -0.4711007, -6.001684, -2.3176537, -0.08661085, -5.9372387, -2.2194543, 0.11079419, -5.824459, -1.739311, 0.72020924, -5.445842, -1.4669368, 1.6421381, -0.30746174, -1.4669368, 1.6421381, 1.965394, -1.825623, 0.6985105, -5.445842, -2.3812249, 0.40134466, -4.392848) points = PackedVector3Array(2.639865, -0.93180054, 2.1575794, 2.5861135, 1.1470379, -1.4858942, 2.3804116, 0.5341828, 5.2797356, 2.3804116, 0.18806255, 5.32922, 2.3804116, -0.8661753, 4.864291, 2.3804116, -1.0148906, 4.0564213, 2.6011019, -0.9791671, 0.85025597, 2.590765, -0.8667045, -2.7230182, 2.590765, -0.28533888, -2.7966702, 1.4661236, 1.6421381, -0.30746174, 1.4661236, 1.6421381, 1.965394, 2.2072706, 0.77604365, 5.2682266, 2.4093547, -0.27607727, -5.989025, 2.3804116, 0.40134466, -4.392848, 2.2186413, 0.11079419, -5.824459, 1.82481, 0.6985105, -5.445842, 2.3230424, -0.08025998, 5.6525984, 2.212439, -0.45231283, 5.6169233, 0.3802452, -0.5354029, 5.61232, -2.3812249, -0.8661753, 4.864291, -2.3812249, -1.0148906, 4.0564213, 2.3804116, -1.0148906, -4.7944813, 2.3804116, -0.9804902, -5.7243385, 0.8805454, 1.6670123, -0.30746174, 1.7379808, 0.72020924, -5.445842, 1.0908988, 0.8818908, -5.445842, 0.8805454, 1.6670123, 1.965394, 0.9823625, 1.0935851, 5.340728, 1.5581212, 1.056274, 5.295847, 2.2506852, -0.2766065, -5.998232, 1.3152068, -0.28031117, -6.0511694, 0.3802452, -0.28401583, -6.102956, 0.3802452, -0.05273974, 5.649146, -2.310418, -0.08025998, 5.6537495, -0.38105845, -0.5354029, 5.61232, -2.1574335, -0.42452794, 5.6169233, -2.3812249, 0.18806255, 5.32922, -2.640161, -0.93180054, 2.1575794, -2.601915, -0.9791671, 0.85025597, -2.3812249, -1.0148906, -4.7944813, -2.3812249, -0.9804902, -5.7243385, 0.3802452, -0.4711007, -6.001684, 0.3802452, 1.6881818, -0.30746174, -1.0917118, 0.8818908, -5.445842, -0.38105845, 1.6884462, -0.30746174, 0.3802452, 1.6881818, 1.965394, -0.98317564, 1.0935851, 5.340728, -0.38105845, 1.6884462, 1.965394, -0.38105845, -0.28401583, -6.102956, -0.38105845, -0.05273974, 5.649146, -2.3812249, 0.5341828, 5.2797356, -2.3812249, 0.4148401, 5.296997, -1.559451, 1.056274, 5.295847, -2.2086005, 0.77604365, 5.2682266, -2.5869267, 1.1470379, -1.4858942, -2.5920951, -0.28533888, -2.7966702, -2.5920951, -0.8667045, -2.7230182, -2.415853, -0.28401583, -6.0488677, -2.390011, -0.7981685, -5.8094983, -1.3129189, -0.28401583, -6.0787888, -0.38105845, -0.4711007, -6.001684, -2.3176537, -0.08661085, -5.9372387, -2.2194543, 0.11079419, -5.824459, -1.739311, 0.72020924, -5.445842, -1.4669368, 1.6421381, -0.30746174, -1.4669368, 1.6421381, 1.965394, -1.825623, 0.6985105, -5.445842, -2.3812249, 0.40134466, -4.392848)
[node name="Car" type="RigidBody3D" node_paths=PackedStringArray("wheels")] [node name="Car" type="RigidBody3D" node_paths=PackedStringArray("front_right", "front_left", "back_right", "back_left")]
mass = 10000.0 mass = 1000.0
script = ExtResource("1_uoj53") script = ExtResource("1_uoj53")
wheels = [NodePath("WheelRR"), NodePath("WheelFR"), NodePath("WheelFL"), NodePath("WheelRL")] front_right = NodePath("WheelFR")
front_left = NodePath("WheelFL")
back_right = NodePath("WheelRR")
back_left = NodePath("WheelRL")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."] [node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(0.36002815, 0, 0, 0, 0.36002856, 0, 0, 0, 0.36002815, -0.010458469, 0.12041265, -0.23569715) transform = Transform3D(0.36002815, 0, 0, 0, 0.36002856, 0, 0, 0, 0.36002815, -0.010458469, 0.12041265, -0.23569715)
@@ -20,10 +23,12 @@ shape = SubResource("ConvexPolygonShape3D_7822p")
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5505377, 0.29083502, -2.049065) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5505377, 0.29083502, -2.049065)
[node name="WheelRR" parent="." instance=ExtResource("3_k61xc")] [node name="WheelRR" parent="." instance=ExtResource("3_k61xc")]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0.883119, -0.15691829, 0.9406) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.883119, -0.15691829, 0.9406)
flipped = true
[node name="WheelFR" parent="." instance=ExtResource("3_k61xc")] [node name="WheelFR" parent="." instance=ExtResource("3_k61xc")]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0.883119, -0.13746506, -1.6053799) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.883119, -0.13746506, -1.6053799)
flipped = true
[node name="WheelFL" parent="." instance=ExtResource("3_k61xc")] [node name="WheelFL" parent="." instance=ExtResource("3_k61xc")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9021299, -0.15691829, -1.6053799) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9021299, -0.15691829, -1.6053799)

View File

@@ -32,7 +32,7 @@ shadow_enabled = true
environment = SubResource("Environment_0xm2m") environment = SubResource("Environment_0xm2m")
[node name="Camera3D" type="Camera3D" parent="."] [node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(0.25682604, -0.12386126, 0.95848775, 0.032057658, 0.99229956, 0.11964079, -0.9659258, 0, 0.25881907, 4.482925, 4.2054358, -35.488564) transform = Transform3D(0.96653086, -0.21564756, -0.1389759, 0.12064472, -0.09602227, 0.98804075, -0.22641337, -0.97173876, -0.06679173, -2.64523, 9.843718, -35.668438)
[node name="CSGBox3D2" type="CSGBox3D" parent="."] [node name="CSGBox3D2" type="CSGBox3D" parent="."]
transform = Transform3D(-1.0000001, 0, 0, 0, -1.0000001, 0, 0, 0, 1, -5.7605286, 1.5558312, -35.098152) transform = Transform3D(-1.0000001, 0, 0, 0, -1.0000001, 0, 0, 0, 1, -5.7605286, 1.5558312, -35.098152)

View File

@@ -19,6 +19,19 @@ config/icon="res://icon.svg"
window/stretch/mode="viewport" window/stretch/mode="viewport"
[input]
"Steer 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)
]
}
"Steer 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":97,"location":0,"echo":false,"script":null)
]
}
[physics] [physics]
3d/physics_engine="Jolt Physics" 3d/physics_engine="Jolt Physics"

View File

@@ -2,12 +2,15 @@ class_name Wheel
extends RayCast3D extends RayCast3D
@export var wheel_radius: float = 0.316 @export var wheel_radius: float = 0.316
@export var flipped: bool = false
@export_group("Suspension")
@export var suspension_rest_length: float = 0.1 @export var suspension_rest_length: float = 0.1
@export var suspension_stiffness: float = 250_000 @export var suspension_stiffness: float = 30_000
@export var suspension_damping: float = 2000 @export var suspension_damping: float = 2000
func _ready() -> void: func _ready() -> void:
target_position *= suspension_rest_length + wheel_radius target_position *= suspension_rest_length + wheel_radius
$"RX-Wheel".rotate_y(PI if flipped else 0.0)
func apply_forces(car: Car) -> void: func apply_forces(car: Car) -> void:
force_raycast_update() force_raycast_update()