RandoBots AI Algorithm

RandoBots is a VS arena game we built for Ludum Dare 51.

Two players are on the game field - one is a turret shooting bullets, and one is a "race car" drifting and trying to avoid these bullets. The attacker and avoider switch roles every 10 seconds - the car becomes a stationary turret and the turret becomes a car.

screen3.png

It's basically a symmetric two-player game. But a human companion is not always available! So we wrote an AI algorithm controlling one of the players, allowing you to play against the computer.

In this post I'll explain these algorithms and elaborate on the technical part and also on the game-design aspects of coding an AI player.

Turret AI

Let's start with the simpler one - the turret, its goal is to shoot at the player.

Turret AI consists of two phases:

1. Choose target position

First we need to decide the desired turret direction. The obvious is - towards the other player! But since bullets take time to reach their target, in that case all the opponent needs to do is to keep moving.

A better option is to shoot where the car is headed. For that case we came up with the following calculation:

target_position = car_position + car_velocity * (distance(car, turret) / bullet_speed) * 0.75

In human words:
Predict where the car will be when the bullets hit it; consider the time it will take to bullets to reach the car (distance / bullet speed), and multiply it with the car velocity to get the difference you need to "add" to the current car position. These bullets would almost certainly hit the car if it keeps going in the same speed in the same directions.

But hey, what's that 0.75 factor at the end? Well, after some playtesting, we figured that an AI that is perfectly able to predict your position is not very fun. It was too hard, it felt like it's "cheating", and somewhat inhuman. This "avoider" optimal experience should be - driving fast, drifting around and avoiding. But with this "perfect" turret (before applying the 0.75 factor), the best strategy is to make small moves and avoid each bullet "matrix style" which is much harder. But with the 0.75 correction, speed is your friend. As long as you are going fast enough you can still avoid the bullets, which turned out to be more fun!

2. Control the Turret - Follow the target

We used Godot input system, and the AI mocks actual player keystrokes. The turret would turn right or left, whichever will bring it closer to the target; And if the angle is close enough to the target, it starts shooting (we didn't want the turret to shoot if pointing too far from the target. Nothing wrong with it strategically, it just felt messy).

The result - A "smart" AI turret that follows the player. The white crosshair is the turret's target:

turretemtarget/em3mb.gif

Car AI

Here's the real challenge. The car needs to avoid bullets, but also drive through an ever-changing environment, with walls appear and disappear all the time.

1. Choose target position

Similar to the turret, first of all the car needs to decide where it wants to go. It determines the target point that is the farthest from all the following: - enemy (turret) position - bullet positions - current car position - screen corners

The first two are obvious - you want to get as far as you can from things that kill you.
Then, the car chooses a point that is farthest from its current position. It assumes that the enemy probably already shoots at where you are, and the best thing to do is to keeps moving .
These rules might push the car to choose one of the screen corners, which is not a really good idea, because it can get, well, cornered there... So adding the corners as points to stay away from solved that.

So, we got a target! But how will the car get there?

2. Flow field

Once we have a target position, we need the car to get there. We could just calculate the shortest path (overcoming walls) and let the car go through this path. But - what if the car accidentally slides away from this path? What if it gets hit by bullets on the way and moves out of this path?
That's why we chose flow field pathfinding. We split the game area to 16x16 pixel tiles, and used a form of BFS to calculate for each tile in what direction that would bring the car to the target in the shortest path.

3. Control the Car

Now that we know how to navigate from every point of the screen, we need, again, to mock user input. We calculate on which tile the car is on. Then, according to the tile's calculated direction, we both accelerate and steer the car towards the tile's flow direction.

4. Choose a new target.

Once the car is close enough to the target, we choose a new target according to step 1. The fact that the target is farthest from the car's current position makes sure that the new target is far enough.
If the target is "behind" the car, then it makes a nice tire-screeching drift, as the car quickly turns around towards the new target.

The result:

caremai/em2.gif

caremai/em1.gif

The car navigates towards the target, bypassing walls, always accelerating towards the fastest route to the target.

I could think of ways to optimize this, like recalculate the flow field every time a wall is destroyed (and potentially find a faster route), or actively avoid bullets. But the current behavior was unpredictable and was quite challenging to beat, which was definitely enough for the jam, so we kept it.

Did you enjoy RandoBots AI? Did you find any glitches or bugs in the AI? How would you approach this problem? Please let us know!

And most importantly,

Play RandoBots now in your browser!

Sincerely yours,
Ori and RandoBots team.