Skip to content

Instantly share code, notes, and snippets.

@idbrii
Created December 29, 2022 19:27
Show Gist options
  • Save idbrii/ba09735d9883a1ffb807c7df435eaefd to your computer and use it in GitHub Desktop.
Save idbrii/ba09735d9883a1ffb807c7df435eaefd to your computer and use it in GitHub Desktop.
A 3d kinematic car for Godot 3.5
extends KinematicBody
class_name KinematicCar
# Based on MIT-licensed car tutorial from KidsCanCode
# https://kidscancode.org/godot_recipes/3.x/2d/car_steering/
# https://github.com/kidscancode/godot_recipes/blob/master/src-3/content/2D/car_steering.md
# Ported some features from https://kidscancode.org/godot_recipes/3.x/3d/kinematic_car/car_base/
export(float, -100, 0, 1) var gravity := -20.0
export(float, 0.001, 180, 1) var max_steering_angle := 15
export(float, 0, 5, 0.1) var steering_exaggeration := 1.2
export(float, 0, 1000, 1) var engine_power := 100.0
export(float, -1000, 0, 1) var brake_power := -25.0
export(float, -10, 0, 0.01) var friction := -0.1
export(float, -10, 0, 0.01) var drag := -0.1
export(float, 0.001, 1000, 1) var max_speed_reverse := 25.0
export(float, 0.001, 1000, 1) var slip_speed := 5.0
export(float, 0.001, 10, 1) var traction_fast := 0.1
export(float, 0.001, 10, 1) var traction_slow := 0.7
# Wheel nodes
export(NodePath) var front_wheel_left_path = null
export(NodePath) var front_wheel_right_path = null
onready var front_wheel_left := get_node(front_wheel_left_path) as Spatial
onready var front_wheel_right := get_node(front_wheel_right_path) as Spatial
export(NodePath) var rear_wheel_left_path = null
export(NodePath) var rear_wheel_right_path = null
onready var rear_wheel_left := get_node(rear_wheel_left_path) as Spatial
onready var rear_wheel_right := get_node(rear_wheel_right_path) as Spatial
onready var wheel_base := (front_wheel_left.global_translation - rear_wheel_left.global_translation).length()
var acceleration = Vector3.ZERO
var velocity = Vector3.ZERO
var steer_direction
func _physics_process(dt):
acceleration = Vector3.ZERO
get_input()
apply_friction()
calculate_steering(dt)
velocity += acceleration * dt
velocity = move_and_slide(velocity)
func apply_friction():
if velocity.length() < 0.2:
velocity = Vector3.ZERO
var friction_force = velocity * friction
var drag_force = velocity * velocity.length() * drag
acceleration += drag_force + friction_force
func get_input():
var turn = Input.get_axis("move_right", "move_left")
steer_direction = turn * deg2rad(max_steering_angle)
if Input.is_action_pressed("accelerate"):
acceleration = -transform.basis.z * engine_power
if Input.is_action_pressed("brake"):
acceleration = -transform.basis.z * brake_power
func calculate_steering(dt):
# Ref: http://engineeringdotnet.blogspot.com/2010/04/simple-2d-car-physics-in-games.html
var rear_wheel = transform.origin + transform.basis.z * wheel_base / 2.0
var front_wheel = transform.origin - transform.basis.z * wheel_base / 2.0
rear_wheel += velocity * dt
front_wheel += velocity.rotated(transform.basis.y, steer_direction) * dt
var new_heading = (front_wheel - rear_wheel).normalized()
var traction = traction_slow
if velocity.length() > slip_speed:
traction = traction_fast
var d = new_heading.dot(velocity.normalized())
if d > 0:
velocity = velocity.linear_interpolate(new_heading * velocity.length(), traction)
if d < 0:
velocity = -new_heading * min(velocity.length(), max_speed_reverse)
look_at(transform.origin + new_heading, transform.basis.y)
var wheel_turn = steer_direction * steering_exaggeration
front_wheel_right.rotation.y = wheel_turn
front_wheel_left.rotation.y = wheel_turn
func _calculate_max_speed() -> float:
# Tried to expose as an export var, but couldn't figure it out.
# Source: https://github.com/kidscancode/godot_recipes/issues/22#issuecomment-1027965700
if drag >= 0 and friction >= 0:
return -1.0
elif drag >= 0 and friction < 0:
return engine_power / friction
elif drag < 0 and friction >= 0:
return sqrt(engine_power / drag)
var discriminant: float = (friction * friction) - (4 * drag * engine_power)
return (-friction - sqrt(discriminant)) / (2 * drag) if discriminant >= 0 else -1.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment