I tries different scripts to make the vehicle follow a path, but it follows but not in a staright way, it keeps snaking. Here is one of the scripts I tired.
extends VehicleBody
# Path Following
export(NodePath) var path_node
export var base_look_ahead : float = 8.0 #5.0
export var speed_look_ahead_multiplier : float = 1.0 #0.5
# Vehicle Settings
export var target_speed : float = 15.0
export var max_engine_force : float = 150.0
export var max_braking_force : float = 10.0
export var max_steering_angle : float = 0.6
export var steering_speed : float = 2.0 #4.0
# --- NEW: Stuck & Recovery Settings ---
export var stuck_speed_threshold : float = 1.0
export var stuck_time_threshold : float = 1.5
export var reverse_duration : float = 2.0
export var reverse_engine_force : float = 100.0
var stuck_timer : float = 0.0
var reverse_timer : float = 0.0
var is_reversing : bool = false
var reverse_steer_dir : float = 0.0
# --------------------------------------
# References
var path : Path
onready var ray_forward = $RayCastForward
onready var ray_left = $RayCastLeft
onready var ray_right = $RayCastRight
func _ready():
if path_node:
path = get_node(path_node)
else:
push_warning("Path Node not assigned to AI Vehicle!")
func _physics_process(delta):
if not path:
return
var current_speed = linear_velocity.length()
# 1. RECOVERY STATE HANDLING
# If the car is currently reversing, ignore pathfinding temporarily
if is_reversing:
reverse_timer -= delta
engine_force = -reverse_engine_force # Negative force moves it backward
brake = 0.0
# Smoothly turn the wheels to the recovery angle
steering = lerp(steering, reverse_steer_dir, steering_speed * delta)
# End the reversing state when the timer runs out
if reverse_timer <= 0.0:
is_reversing = false
stuck_timer = 0.0
return # Skip the rest of the physics process until done reversing
# 2. PATH TRACKING
var local_pos = path.to_local(global_transform.origin)
var curve = path.curve
var current_offset = curve.get_closest_offset(local_pos)
var look_ahead = base_look_ahead + (current_speed * speed_look_ahead_multiplier)
var target_offset = current_offset + look_ahead
var local_target_point = curve.interpolate_baked(target_offset)
var global_target_point = path.to_global(local_target_point)
# 3. OBSTACLE AVOIDANCE
var avoid_steer = 0.0
var is_blocked = false
if ray_forward.is_colliding():
is_blocked = true
avoid_steer = -max_steering_angle
elif ray_left.is_colliding():
avoid_steer = -max_steering_angle
elif ray_right.is_colliding():
avoid_steer = max_steering_angle
# 4. STEERING CALCULATION
# var desired_steer = 0.0
# if avoid_steer != 0.0:
# desired_steer = avoid_steer
# else:
# var target_local_dir = to_local(global_target_point)
# var steer_angle = atan2(target_local_dir.x, -target_local_dir.z)
# desired_steer = clamp(steer_angle, -max_steering_angle, max_steering_angle)
#
# steering = lerp(steering, desired_steer, steering_speed * delta)
# 4. STEERING CALCULATION
var desired_steer = 0.0
if avoid_steer != 0.0:
desired_steer = avoid_steer
else:
var target_local_dir = to_local(global_target_point)
var steer_angle = atan2(target_local_dir.x, -target_local_dir.z)
desired_steer = clamp(steer_angle, -max_steering_angle, max_steering_angle)
# --- NEW: Steering Deadzone ---
# If the steering angle is extremely small, force it to 0
# This prevents the AI from making endless micro-corrections
if abs(desired_steer) < 0.05:
desired_steer = 0.0
steering = lerp(steering, desired_steer, steering_speed * delta)
# 5. ACCELERATION & BRAKING
if is_blocked and ray_forward.get_collider():
engine_force = 0.0
brake = max_braking_force
else:
brake = 0.0
if current_speed < target_speed:
engine_force = max_engine_force
else:
engine_force = 0.0
# 6. STUCK DETECTION (Triggers the Recovery State)
# If the car is moving slower than the threshold, start the timer
if current_speed < stuck_speed_threshold:
stuck_timer += delta
if stuck_timer > stuck_time_threshold:
# We've been stuck too long! Initiate reverse sequence
is_reversing = true
reverse_timer = reverse_duration
# Determine which way to steer while reversing to swing the front end clear.
# If the obstacle is on the right, steer left while reversing, and vice versa.
if ray_right.is_colliding():
reverse_steer_dir = max_steering_angle
else:
reverse_steer_dir = -max_steering_angle
else:
# Car is moving fine, reset the stuck timer
stuck_timer = 0.0