How do i make racing ai drift?

Godot Version

4.2

Question

I used the kids can code context map tutorial to make a racing AI but I don’t know how to make the AI drift.

I also used the kids can code car movement so I want the ai’s to be similar.

here is my code if anybody can help.

extends CharacterBody2D
class_name RayAi1 

@export_group("Rand Speed")
@export var rand_speed: bool
@export var min_speed = 150
@export var max_speed = 200
@export var desiered_speed = 150

@export_group("Rand Look Ahead")
@export var rand_look_ahead: bool
@export var min_look_ahead = 100
@export var max_look_ahead = 200
@export var look_ahead = 120

@export_group("other")
@export var steer_force = 0.1
@export var num_rays = 15

var traction: float

var is_drifting = false
var steer_direction
# context array
var ray_directions = []
var interest = []
var danger = []

var chosen_dir = Vector2.ZERO
var vel = Vector2.ZERO
var acceleration = Vector2.ZERO

func call_on_ready():
	interest.resize(num_rays)
	danger.resize(num_rays)
	ray_directions.resize(num_rays)
	for i in num_rays:
		var angle = i * 2 * PI / num_rays
		ray_directions[i] = Vector2.RIGHT.rotated(angle)

func call_in_physics_process(delta):
	if rand_speed:
		desiered_speed = randi_range(min_speed, max_speed)
	if rand_look_ahead:
		look_ahead = randi_range(min_look_ahead, max_look_ahead)
		var yip = 0
	set_interest()
	set_danger()
	choose_direction()
	var desired_velocity = chosen_dir.rotated(rotation) * desiered_speed
	velocity = velocity.lerp(desired_velocity, steer_force)
	rotation = velocity.angle()

	move_and_collide(velocity * delta)


func set_interest():
	# Set interest in each slot based on world direction
	if owner and owner.has_method("get_path_direction"):
		var path_direction = owner.get_path_direction(position)
		for i in num_rays:
			var d = ray_directions[i].rotated(rotation).dot(path_direction)
			interest[i] = max(0, d)
	# If no world path, use default interest
	else:
		set_default_interest()

func set_default_interest():
	# Default to moving forward
	for i in num_rays:
		var d = ray_directions[i].rotated(rotation).dot(transform.x)
		interest[i] = max(0, d)

func set_danger():
	# Cast rays to find danger directions
	var _space_state = get_world_2d().direct_space_state
	for i in num_rays:
		var params = PhysicsRayQueryParameters2D.create(position,
		 position + ray_directions[i].rotated(rotation) * look_ahead)
		var result = get_world_2d().direct_space_state.intersect_ray(params)
		danger[i] = 1.0 if result else 0.0

func choose_direction():
	# Eliminate interest in slots with danger
	for i in num_rays:
		interest[i] -= danger[i] 
	# Choose direction based on remaining interest
	chosen_dir = Vector2.ZERO
	for i in num_rays:
		chosen_dir += ray_directions[i] * interest[i]
	chosen_dir = chosen_dir.normalized()



What does drifting mean to you? Is it an animation? Is it a physical slipping of the car tires?

here is what I use for the player. I want it to be similar (the code is from the kids can code steering tutorial)

I’d appreciate it if you can help :smiley:

	
func calculate_steering(delta):
	var rear_wheel = position - transform.x * wheel_base / 2.0
	var front_wheel = position + transform.x * wheel_base / 2.0
	rear_wheel += velocity * delta
	front_wheel += velocity.rotated(steer_direction) * delta
	var new_heading = rear_wheel.direction_to(front_wheel)
	#starts drifting
	if velocity.length() > slip_speed and Input.get_axis("left", "right"):
		is_drifting = true
	elif velocity.length() > slip_speed/1.7 and Input.is_action_just_pressed("backward"):
		is_drifting = true
	elif !Input.get_axis("left", "right") or velocity.length() < slip_speed/1.7:
		is_drifting = false
		
	var d = new_heading.dot(velocity.normalized())
	if d > 0:
		velocity = lerp(velocity, new_heading * velocity.length(), traction * delta)
	if d < 0:
		velocity = -new_heading * min(velocity.length(), max_speed_reverse)
	rotation = new_heading.angle()


func drifting(drift_var = is_drifting):
	var car_is_drifting = drift_var
	if car_is_drifting == true:
		traction = traction_fast
		$Drift_effect_partical.emitting = true
		$Drift_effect_partical2.emitting = true
	else:
		traction = traction_slow
		$Drift_effect_partical.emitting = false
		$Drift_effect_partical2.emitting = false

From what I can tell about the ai is that it moves and slides with sensed directions. lerping it’s rotation based on velocity angle and direction with some random gas pedal.

Now the drifting code uses speed and player input axis turning or player input back to start drifting. Only stopping the drift once speed falls or steering stops.

You can get speed by calculating the length of velocity after this point. And you can determine if the AI is turning if you find the difference of rotation and velocity angle before this point.

var stearing = rotation - velocity.angle()
rotation = velocity.angle()

Then with speed and stearing variables you can use this logic from the player. Replacing input get axis with stearing

I don’t know how to replicate the backwards. Since the AI doesn’t break?

Also this may require more tuning of the AI since it may not handle the drift physics very well. But let’s see what happens with activating drift traction on the ai.

A better way to approach ai, is to use the same vehicle code. But in order to do that you need to encapsulate and cache the player input on a separate node, and set variables on the vehicle that will later be used in the physics process.

In this way, you write all the animation and driving logic once and then either place a ai node to drive it, or a player input node to drive it.

1 Like

so basically write a car class with all the logic(drifting, acceleration, etc.)
and use that for the ai and player movement?

Yes.

Understanding the AI code where it casts rays and chooses a direction to move and slide. Is a tuning in itself.

If you generally like how the ai navigates as is, then I wouldn’t make a singular vehicle class with an input interface (for ai or player). You would use the variables I mentioned above to just play the animations and not change the AI physics. The movements might not match between player and AI, but that’s a compromise you would have to decide…

In the end It’s just double the work, and if you change something on one you may have to do the same thing on the other.

I don’t know what the upfront cost to make a singular vehicle with the AI re-tuning is. It’s just my opinion, but I would approach it like that.

1 Like