Skip to content

Technical: Driver AI

Natan Maia edited this page Feb 21, 2024 · 8 revisions

Basics

AI should be implemented as a component that can be added to the karts (in this Repo, inheriting from KartInput). This "separation of concerns" means features only used by the AI like collision sensors, navigation agents and taxing vector math can be instanced, enabled and disabled separately.

As a developer, your priorities for this system should be, in order:

  1. The AI can successfully drive the kart around the track;
  2. The AI can drive the kart around while obstacles are thrown at them;
  3. The AI can compete and race its way to 1st place, if given reasonable advantages.

Driving

todo

Driving with Obstacles

Obstacles here have a particular meaning: anything that's dynamic, not static. This may include other racers, or items, or moving sections of the track like drawbridges, gates and moving platforms.

This doesn't require obstacle avoidance, per se; as a player, you don't want CPU controlled opponents that can perfectly dodge all your tools. The goal here is to make the AI able to recover itself after such events and get back to racing. It can't get stuck after running over an e.g. oil spill, or not be able to drive on a moving platform as it's not in the navigation mesh.

This will usually require some sort of state machine to determine if the AI is on track or stranded off-track, if it's driving on reverse or not. Worst case scenario, if the kart gets stuck for too long, you can warp it back to the track.

Avoidance is still desirable, however. AI drivers should avoid direct contact with other karts as that can disrupt steering for both. Steering away from traps and track gimmicks also makes the AI seem more responsive, helping with the game's immersion and making it more fun.

Competing

The AI should also know that it is racing with the goal of getting to 1st place, and try to act as such. It should not use the brakes as its main form of collision avoidance as that can slow it down massively, and mostly rely on steering. If the AI driver is going faster than the driver in front of it, it should try to overtake from the inside.

If the AI has an offensive item, it should use it when there's a reasonable chance of hitting another driver. If it has a defensive item, it might choose to wait to use it only when in danger. The AI should also consider different paths like shortcuts if it's too far behind or fighting for a higher ranking, especialy if it has a "boost" item in its possession.

Of course, in an accessible party game like a kart racer the AI shouldn't always make the most optimal choices, and such "expert" behavior should be less frequent in easier difficulties. Making those kinds of decisions, though, shows the player they're not just pushovers and should be paid attention to.

Racing Paths

The simplest approach to racing AI is to define a "racing line" as a Path3D, and have AI drivers follow that path. Worst case scenario, drivers can be programmed to follow the path exactly, as if "on-rails", which could be acceptable for a 90's shovelware game but that's it. We can do better and use these paths for guiding steering, which still lets AI react to being thrown off its path.

image

In a serious racing game, this path should follow the actual racing line, but in a kart game where drivers generally go slower and aren't as punished for bad racing lines, having the AI path start from the middle of the track is a safe option. There are still concerns to address while making that path, like aligning it to the terrain, shifting it away from corners with no railings, and starting sharp corners a bit earlier from the outside.

image

If you find the drivers will naturally understeer in a sharp corner, make the suggested path closer to the inside

One interesting evolution of this path concept is to make separate "center", "inside" and "outside" paths through the horizontal width of the track, and allow the AI drivers to switch between them. Different paths through the same roads make the drivers feel more natural and less on-rails, and also helps with programming racing situations like blocking and overtaking.

Some tracks

Navigation

Intersections

Paths might struggle with this too, but pathfinding algorithms struggle with this problem a lot: If the track intersects itself, or gets close to doing it (like two-lane straights, or overpasses/underpasses, loops), pathfinding will either think the target position is on the other side of the intersection, or keep switching between the two. As such, you need some way to separate those sections of the track so that the AI can't pathfind from one to the other.

One solution in Godot (that we're yet to investigate) is to split the track in a few Navigation Layers (e.g. one layer per different elevation) and use trigger zones to change which layer the navigation agent should pathfind to. This could also be an apt solution for split pathways.

Todo

write about navigation and pathfinding. write about implementation of driver and obstacle avoidance. write about rubberbanding.

Bibliography

https://youtu.be/SKXqWcaoTGE?si=8yV8Q9nSEjdV45vU&t=1209

https://www.youtube.com/watch?v=-juhGgA076E

https://www.gameaipro.com/GameAIPro/GameAIPro_Chapter38_An_Architecture_Overview_for_AI_in_Racing_Games.pdf

Clone this wiki locally