# How do i make racing ai drift?

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("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

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)
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,
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

``````
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
#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

if d > 0:
velocity = lerp(velocity, new_heading * velocity.length(), traction * delta)
if d < 0:
velocity = -new_heading * min(velocity.length(), max_speed_reverse)

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

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.