Added engine force, air resistance, and rolling resistance

also added debug draw 3d addon
This commit is contained in:
Wheelbarrow
2025-07-26 10:16:43 -04:00
parent a28e7d6d13
commit 15547fce8d
40 changed files with 566 additions and 18 deletions

View File

@@ -3,40 +3,98 @@ extends RayCast3D
@export var wheel_radius: float = 0.316
@export var flipped: bool = false
@export var on_drivetrain: bool = false
@export var rolling_resistance: float = 2
@export_group("Suspension")
@export var suspension_rest_length: float = 0.1
@export var suspension_stiffness: float = 30_000
@export var suspension_damping: float = 2000
var car: Car
var _last_velocity: Vector3
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:
func set_new_car(new_car: Car) -> void:
car = new_car
# Little bit freaky but we put up with it
_last_velocity = car.get_velocity_at_point(get_collision_point())
func _physics_process(_delta: float) -> void:
force_raycast_update()
var force: Vector3 = get_suspension_force(car)
car.apply_force(force, car.to_local(get_collision_point()))
apply_suspension_force()
apply_rolling_resistance()
apply_engine_force()
_last_velocity = car.get_velocity_at_point(get_collision_point())
func get_suspension_force(car: Car) -> Vector3:
func apply_suspension_force() -> void:
var up: Vector3 = global_basis.y
if not is_colliding():
$"RX-Wheel".position = -up * suspension_rest_length
return Vector3.ZERO
return
var collision_point: Vector3 = to_local(get_collision_point())
var wheel_center: Vector3 = collision_point + (up * wheel_radius)
var wheel_center: Vector3 = get_wheel_center()
$"RX-Wheel".position = wheel_center
var suspension_length: float = -up.dot(wheel_center)
var suspension_displacement: float = suspension_rest_length - suspension_length
#https://en.wikipedia.org/wiki/Hookes_law
var hookes_force_scalar: float = suspension_stiffness * suspension_displacement
var wheel_velocity: Vector3 = car.get_velocity_at_point(car.to_local(to_global(wheel_center)))
var wheel_velocity: Vector3 = car.get_velocity_at_point(to_global(wheel_center))
var wheel_up_velocity: float = up.dot(wheel_velocity)
var damping_force_scalar: float = suspension_damping * wheel_up_velocity
var y_force_scalar: float = hookes_force_scalar - damping_force_scalar
var force: Vector3 = Vector3.UP * y_force_scalar
var force: Vector3 = up * y_force_scalar
return force
DebugDraw3D.draw_arrow(
to_global(wheel_center),
to_global(wheel_center + force / 1000),
Color.RED,
.2
)
car.apply_force(force, car.to_local(to_global(wheel_center)))
func apply_rolling_resistance() -> void:
if not is_colliding(): return
var normal: Vector3 = get_collision_normal()
var velocity: Vector3 = car.get_velocity_at_point(get_collision_point())
velocity -= normal * normal.dot(velocity)
var force: Vector3 = -rolling_resistance * velocity
var arrow_tail: Vector3 = to_global(get_wheel_center())
car.apply_force(force, car.to_local(get_collision_point()))
DebugDraw3D.draw_arrow(
arrow_tail,
arrow_tail + force,
Color.ORANGE,
.2
)
func apply_engine_force() -> void:
if not on_drivetrain: return
if not is_colliding(): return
var forwards: Vector3 = -global_basis.z
var torque: float = car.get_torque_per_wheel()
var force: Vector3 = forwards * torque / wheel_radius
var arrow_tail: Vector3 = to_global(get_wheel_center())
car.apply_force(force, car.to_local(get_collision_point()))
DebugDraw3D.draw_arrow(
arrow_tail,
arrow_tail + force / 250,
Color.BLUE,
.2
)
func get_wheel_center() -> Vector3:
var up: Vector3 = global_basis.y
var collision_point: Vector3 = to_local(get_collision_point())
return collision_point + (up * wheel_radius)