1. Introduction
2. Graphics
3. Physics
4. Collision Detection
5. Computer AI (You’re here!)
6. Screen Transitions
7. Postmortem

### Player and CPU Input (If you haven’t seen Short Circuit yet, go watch it!)

Fundamental to any video game is player input. Without it, there’s no way to interact with the game, and very little else can happen. There are some exceptions – Plantera and its upcoming sequel essentially play themselves and are very good. But lets be real, a rocket-powered soccer car game is kind of boring if you can’t do anything.

In previous articles we touched a bit on how Pocket League players can jump, drive and roll based on buttons they pressed. Mostly, we glossed over this by saying something like “the car jumps when the player presses A”. Technically, this is the truth, but there is more behind it, such as limiting controls while the timer counts down or preventing the car from rolling when on the ground. Furthermore, the non-player car also needs to be able to make the same movements, and that car should also be constrained by the same rules as the player.

Let’s dig into how this was accomplished.

### Reading Gameboy Input with GBDK

First, a little background, especially for those not used to bitmasks and bitwise operations.

GBDK uses an 8 bit unsigned integer to store the current state of the joypad – all the buttons like Start, Select, A, B, and the D-Pad directions. This number can have a value of 0 - 255. The actual value of that number is relatively unimportant, since it’s used as a bitmask.

In essence, each bit of the number is a flag that determines which button was pressed. Since it’s an 8 bit number, there must be 8 buttons mapped. We can confirm this by looking at some of the GBDK library code where the button constants are defined:

``````// In gb.h

A logical OR of these is used in the wait_pad and joypad
functions.  For example, to see if the B button is pressed
try
UINT8 keys;
if (keys & J_B) {
...
}
*/
#define	J_START      0x80U
#define	J_SELECT     0x40U
#define	J_B          0x20U
#define	J_A          0x10U
#define	J_DOWN       0x08U
#define	J_UP         0x04U
#define	J_LEFT       0x02U
#define	J_RIGHT      0x01U
``````

These constants are defined in hex, so it’s a little hard to see what’s going on if you’re not used to it. Let’s break it apart a bit. The easiest case is `J_RIGHT` or 0x01:

``````J_RIGHT
hex:     0x01
decimal: 1
binary:  0000 0001
``````

So in this case, the last bit is set to 1. For another button, a different bit will be set to 1:

``````J_DOWN
hex:     0x08
decimal: 8
binary:  0000 1000
``````

And so on. The full mapping goes in order they’re defined above.

GBDK provides a utility function called `joypad` to read the inputs. Note, more than one key can be pressed at a time, so multiple flags can be set! For instance, it might be 0x28 or `0010 1000`, meaning both the B and Down buttons are pressed. Once the inputs are read, we now need to check which ones are pressed so that we can do things.

#### Bitwise Operations (AND and OR)

The most common thing we’re going to want to do in Pocket League is check whether a button is pressed. We can do this easily with the bitwise AND operator (`&`). Using this, we can take any two numbers and return only the bits that are set in both numbers.

Similarly, we can use bitwise OR (`|`) to return the bits that are set in either one number or the other. Pocket League doesn’t use this much for player input, but setting sprite properties in Part 1 relies heavily on bitwise OR. The computer car, as you’ll see, also uses it quite a bit, but in a different way.

Lets see an example so it’s easier to visualize: For the joypad constants like `J_START`, since only a single bit is set, this is particularly useful. If we wanted to check if the Start button is pressed, we can simply AND it with `J_START`:

``````UINT8 input = joypad();

if (input & J_START) {
// Do some things!
}
``````

### Giving the Player Control

I’m going to include the bulk of the `tick_car_physics` function here. We’ve already been over how the actual game physics are calculated, but this time around we will be talking about what it’s doing with the `input1` and `input2` parameter.

``````void tick_car_physics(UINT8 n, UINT8 *x, UINT8 *y, INT8 *d_x, INT8 *d_y, UINT8 *rot, UINT8 input1, UINT8 input2) {
// Jump
if (debounced_input(J_A, input1, input2) && *y == FLOOR) {
*d_y = -JUMP_ACCELERATION;
}

// Drive
if (*y == FLOOR) {
*rot = 0;

if (input1 & J_RIGHT)  {
*d_x += ACCELERATION;
}
else if (input1 & J_LEFT) {
*d_x -= ACCELERATION;
}
else if (!(input1 & J_B)) {
if (*d_x > 0) {
*d_x -= ACCELERATION;

if (*d_x <= 0) {
*d_x = 0;
}
}

if (*d_x < 0) {
*d_x += ACCELERATION;

if (*d_x >= 0) {
*d_x = 0;
}
}
}
}
else {
if (input1 & J_RIGHT)  {
*rot += ROTATION_SPEED;
}
else if (input1 & J_LEFT) {
*rot -= ROTATION_SPEED;
}
}

if (input1 & J_B) {
calculate_boost_velocity_vectors(n, *rot, d_x, d_y);
}
}
``````

As we’ve talked about, this function is essentially a determination of what the car can do based on its position and the input that you give it. There are four main actions: drive, jump, boost, and air roll.

#### `debounced_input`

I want to make special callout to the `debounced_input` function here. It serves one purpose, which is to limit an input from being held. Hence, it takes three parameters (the target button, the current input, and the previous input). If the two match, the button is being held. If it’s not, then the button press is new and we should do something with it:

``````// Check for match on new input BUT NOT old input
INT8 debounced_input(INT8 target, INT8 new, INT8 old) {
return (new & target) && !(old & target);
}
``````

Without this helper function, you could hold down the A button and the car would “bounce” repeatedly. Not good. We want to require a new A press every time you want to jump. `debounced_input` also solves some similar issues with the menu as well, but we won’t go over that here.

### Johnny 5 Pocket League IS ALIVE!

If you don’t get this joke, seriously watch Short Circuit.

You may have caught on at this point, but the CPU car uses the exact same `tick_car_physics` function, so it needs to provide the current and previous inputs in order to work. Conveniently, this means that it’ll behave EXACTLY like the player car – it abides by the same rules. In order to facilitate this, we now simply need to calculate the optimum input for the CPU car, which we do using a function called `calculate_cpu_input`.

Here it is in its entirety, the “brain” of Pocket League:

``````INT8 calculate_cpu_input(UINT8 x, UINT8 y, UINT8 rot, UINT8 ball_x, UINT8 ball_y, INT8 ball_d_x, INT8 ball_d_y) {
UINT8 counter = 0;
UINT8 input = 0x00; // Nothing

while (counter < CPU_PREDICTION) {
tick_ball_physics(
&ball_x, &ball_y, &ball_d_x, &ball_d_y,
255, 255, 255, 255, 0,
255, 255, 255, 255, 0,
1 // skip collision checking
);

counter++;
}

if (int_distance(ball_y, y) < 15) { // Same Y value, should drive if on the floor
if (y == FLOOR) {
if (x < ball_x) {
input = J_RIGHT;
} else {
input = J_LEFT;
}
}
}
else if(int_distance(ball_y, y) >= 15) { // Not same Y, should jump or rotate
if (y == FLOOR && int_distance(ball_x, ball_y) < 20) { // On the floor and close
input = J_A;
} else {
if (ball_x > x) {
input = input | J_RIGHT;
} else {
input = input | J_LEFT;
}
}
}

input = input | J_B;
}

return input;
}
``````

Were you expecting more? It’s really quite simple, and is a very effective analogue for a human player. The second half should be fairly straightforward, as it’s just a determination of whether to drive, jump, or roll. The first part is the only new stuff, so we can walk through it.

#### CPU Prediction

In order for the car to give accurate key presses, it doesn’t need to know where the ball is now, but where it WILL BE when the car intercepts it. The first part of this function calculates the ball’s FUTURE position:

``````  UINT8 counter = 0;

while (counter < CPU_PREDICTION) {
tick_ball_physics(
&ball_x, &ball_y, &ball_d_x, &ball_d_y,
255, 255, 255, 255, 0,
255, 255, 255, 255, 0,
1 // skip collision checking
);

counter++;
}
``````

`CPU_PREDICTION` is a constant (as of Pocket League v0.1.1 it is set to `2`) and determines the number of game ticks to look ahead. Without this, the ball would move from the spot it’s currently in before the car can get there.

The call to `tick_ball_physics` added a flag to skip collision checking with the other cars as it’s expensive to calculate all the hitboxes. It’s also not that important, so we skipped it. It still calculates bounces correctly.

#### Putting It All Together

Now that we know where the ball will be, the CPU car can simply determine whether it should try to drive to it, jump, or rotate while in the air. If the ball is in front of the car, even if it’s rotated, the car should boost towards it to hit it at max speed.

Note that we’re setting the input with bitwise OR (`|`) – This is important because we don’t want to overwrite the existing input! For instance, if we changed the code slightly:

``````  if (rotation_quadrant(rot) == quadrant) {
// input = input | J_B;
input = J_B;
}
``````

This car can no longer rotate AND boost at the same time! ORing the input with the new input ensures multiple key presses still work.

### Limiting Control

There’s one last piece of the puzzle (for both humans and bots). There are cases where we would like to disallow input from either the player or the CPU car. These are:

1. Before the countdown has finished, so that the cars wait til kickoff
2. The CPU car should stop driving once a goal is scored

Let’s look at that code:

``````if (controls_enabled) {
key2 = key1;

if (CPU_DISABLED != 1) {
cpu_key2 = cpu_key1;
cpu_key1 = calculate_cpu_input(cpu_x_pos, cpu_y_pos, cpu_rot, ball_x_pos, ball_y_pos, ball_d_x, ball_d_y);
}

if (score_flag) { // Kill CPU controls after scoring
cpu_key1 = 0x00;
cpu_key2 = 0x00;
}
}
``````

Pretty simple. `controls_enabled` is false before the kickoff completes. And once a goal is made, `score_flag` is true, so we kill the CPU controls. Easy peasy. Note that you can still drive around as a human player!

### Next Time

That’s all there is for this time, folks! Next time, I hope to have made progress on the sound part of the game. I’d also like to talk about how the game transitions from different screens, but it might not take a lot of explaining as the implementation is fairly simple.

I hope you’re continuing to enjoy the series, and thanks for reading!