Godot Version
Godot v4.4
Question
So, basically… I’m making a mario-kart like kart racer game and I need the car to be able to detect if it is touching the ground or not. I am using a raycast to align the car with the ground that it is touching and need that same raycast to be able to detect when the car is touching the ground. It should be simple but for whatever reason, when it is on the ground, it isn’t properly detecting it all of the time…
Example of what’s happening (watch the output)
Here’s the code for the kart:
extends Node3D
@onready var ball: RigidBody3D = $ball
@onready var car_mesh: Node3D = $suv
@onready var ground_ray: RayCast3D = $suv/RayCast3D
@onready var left_wheel: MeshInstance3D = $"suv/wheel-back-left"
@onready var right_wheel: MeshInstance3D = $"suv/wheel-back-right"
@onready var body_mesh: MeshInstance3D = $suv/body
@onready var anim: AnimationPlayer = $suv/AnimationPlayer
@onready var reset_ray: RayCast3D = $ResetRay
@onready var collision_detector: Area3D = $suv/collisionDetector
var sphere_offset = Vector3(0, -1.0, 0)
var acceleration = 40
var steering = 15
var turn_speed = 10
var turn_stop_limit = 0.75
var body_tilt = 70
var sideways_friction = 10
var drift_amount = 0
var turn_lessen = 0
var left = false
var right = false
var speed_input = 0
var rotate_input = 0
var total_input = 0
var ground = true
var drifting = false
var max_speed = 30
var reversing = false
var speed = 0
func _ready():
ground_ray.add_exception(ball)
reset_ray.add_exception(ball)
func snap_position(t: Transform3D) -> void:
ball.global_transform = t
car_mesh.global_transform = t
ball.linear_velocity = Vector3.ZERO
ball.angular_velocity = Vector3.ZERO
func _process(_delta):
var linear_velocity: Vector3 = ball.get_linear_velocity()
var local_linear_velocity: Vector3 = car_mesh.global_transform.basis.inverse() * linear_velocity
if linear_velocity.length() > 0:
reversing = false
elif linear_velocity.length() < 0:
reversing = true
speed = local_linear_velocity.z
# Keep the car mesh aligned with the sphere
car_mesh.transform.origin = ball.transform.origin + sphere_offset
# Accelerate based on car's forward direction
if linear_velocity.length() < max_speed:
ball.apply_central_force(-car_mesh.global_transform.basis.z * speed_input)
var sideways_velocity: float = local_linear_velocity.x
var sideways_force: Vector3 = sideways_velocity * sideways_friction * -car_mesh.transform.basis.x
#Left is positive, Right is negative
if drifting == false:
ball.apply_central_force(sideways_force)
if drifting == true && right == false:
#Drift Left
if rotate_input > .1:
anim.play("driftLeft")
drift_amount = .2
steering = 5
turn_speed = 7
turn_lessen = -0.07
left = true
right = false
#Drift Right
elif rotate_input < -.1 && left == false:
anim.play("driftRight")
drift_amount = -.2
steering = 5
turn_speed = 7
turn_lessen = 0.07
left = false
right = true
elif drifting == false:
steering = 7
turn_speed = 10
turn_lessen = 0
drift_amount = 0
left = false
right = false
func _physics_process(delta):
if ground_ray.is_colliding():
print("ground")
#ground_ray = $suv/RayCast3D
else:
print("air")
#ground_ray = $ResetRay
speed_input = 0
speed_input += Input.get_action_strength("w")
speed_input -= Input.get_action_strength("s")
speed_input *= acceleration
# Get steering input
rotate_input = 0
rotate_input += Input.get_action_strength("a")
rotate_input -= Input.get_action_strength("d")
rotate_input *= deg_to_rad(steering)
total_input = rotate_input + drift_amount + turn_lessen
right_wheel.rotation.y = rotate_input
left_wheel.rotation.y = rotate_input
# rotate car mesh
if ball.linear_velocity.length() > turn_stop_limit:
var new_basis = car_mesh.global_transform.basis.rotated(car_mesh.global_transform.basis.y, total_input)
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
var t = -rotate_input * ball.linear_velocity.length() / body_tilt
body_mesh.rotation.z = lerp(body_mesh.rotation.z, t, 10 * delta)
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)
if Input.is_action_pressed("drift") && speed <= -10:
drifting = true
elif Input.is_action_just_released("drift"):
drifting = false
anim.play("straight")
func align_with_y(xform, new_y):
xform.basis.y = new_y
xform.basis.x = -xform.basis.z.cross(new_y)
xform.basis = xform.basis.orthonormalized()
return xform
If anyone knows why this may be happening or knows a solution it would be greatly appreciated!