Added Ackerman Steering
This commit is contained in:
41
car.gd
41
car.gd
@@ -1,12 +1,49 @@
|
||||
class_name Car
|
||||
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:
|
||||
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
|
||||
func get_velocity_at_point(point: Vector3) -> Vector3:
|
||||
return linear_velocity + angular_velocity.cross(point - center_of_mass)
|
||||
|
||||
15
car.tscn
15
car.tscn
@@ -7,10 +7,13 @@
|
||||
[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)
|
||||
|
||||
[node name="Car" type="RigidBody3D" node_paths=PackedStringArray("wheels")]
|
||||
mass = 10000.0
|
||||
[node name="Car" type="RigidBody3D" node_paths=PackedStringArray("front_right", "front_left", "back_right", "back_left")]
|
||||
mass = 1000.0
|
||||
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="."]
|
||||
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)
|
||||
|
||||
[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")]
|
||||
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")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9021299, -0.15691829, -1.6053799)
|
||||
|
||||
@@ -32,7 +32,7 @@ shadow_enabled = true
|
||||
environment = SubResource("Environment_0xm2m")
|
||||
|
||||
[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="."]
|
||||
transform = Transform3D(-1.0000001, 0, 0, 0, -1.0000001, 0, 0, 0, 1, -5.7605286, 1.5558312, -35.098152)
|
||||
|
||||
@@ -19,6 +19,19 @@ config/icon="res://icon.svg"
|
||||
|
||||
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]
|
||||
|
||||
3d/physics_engine="Jolt Physics"
|
||||
|
||||
5
wheel.gd
5
wheel.gd
@@ -2,12 +2,15 @@ class_name Wheel
|
||||
extends RayCast3D
|
||||
|
||||
@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_stiffness: float = 250_000
|
||||
@export var suspension_stiffness: float = 30_000
|
||||
@export var suspension_damping: float = 2000
|
||||
|
||||
func _ready() -> void:
|
||||
target_position *= suspension_rest_length + wheel_radius
|
||||
$"RX-Wheel".rotate_y(PI if flipped else 0.0)
|
||||
|
||||
func apply_forces(car: Car) -> void:
|
||||
force_raycast_update()
|
||||
|
||||
Reference in New Issue
Block a user