Make Your Own Arduboy Game: Part 7 - Make Pong From Scratch!

Before You Start

Hey! Before you start! Do you mind following me on Twitter? I really spent a lot of time working on this tutorial series. I had to re-write this tutorial twice. It would be great if you took look at the other projects I work on. :slight_smile: http://www.twitter.com/crait

And when you get done, please respond and let me know that you’re done! :smiley:

Previous parts of this series:
Part 1, Part 2, Part 3, Part 4, Part 5, Part 6

This Tutorial

In this tutorial, we’re going to learn more about writing our own functions, switches, and basically combining everything we’ve learned up to this point in order to make a playable version of Pong that you can play against a simple AI.

Switch

Before we begin, I want to teach you about the switch keyword. This one is easy and can really save the amount of code you have to write.

Take a look at this code:

if (dude == 0 ) {
  a = 10;
  b = 2;
} 
else if (dude == 1) {
  c = 3;
} 
else if (dude == 2) {
  a = 0;
  b = 3;
  c = 4;
} 
else if (dude == 3) {
  a = 1;
} 
else if (dude == 4) {
  a = 2;
}

Just by looking at this code, you can tell that there are different sections that are executed depending on the value of dude . You can re-write this same code using the switch keyword. Check this out:

switch (dude) {

  case 0:
    a = 10;
    b = 2;
    break;

  case 1:
    c = 3;
    break;

  case 2:
    a = 0;
    b = 3;
    c = 4;
    break;

  case 3:
    a = 1;
    break;

  case 4:
    a = 2;
    break;

}

The different sections of code are called cases. The value of dude is checked and then then the right case is executed. For example, if dude is equal to 3 the code in the case 3 is run, which is a = 1; . Whenever the break; instruction is reached, the Arduboy jumps out of the switch .

Easy, right? We’ll use this to structure our game’s code.

Planning Our Game

Whew! We’re almost ready to start coding! Let’s plan this game out and then start coding.

By breaking down the project into a series of small steps, it helps me realize how much further I have to go as well as keep me motivated to finish the next step. After each major step, I typically test my game to make sure I didn’t break anything and that the new mechanics are working properly.

To break down our Pong game, we’ll need to follow these steps in development:

  1. Set up the new sketch
  2. Create a title screen, game screen, win screen, and lose screen
  3. Create a ball that bounces around the screen
  4. Create and control a paddle
  5. Create the computer’s paddle
  6. Programming collision
  7. Adjusting the AI
  8. Scoring
  9. Creating a new ball and resetting the game

Don’t worry if these don’t all make sense! I will explain them as we move forward!

1. Creating A New Sketch

Open up your Arduino IDE and create a new sketch. ( File > New ) In the sketch, like always, we’re going to include the Arduboy library, create an Arduboy object, as well as updating our setup()/loop() functions to include the standart display functions. If that sounds like a lot, don’t worry! Just make sure your code looks like this!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;

//Variables declared here

void setup() {
  arduboy.begin();
  //Set-up here
  arduboy.clear();
}

void loop() {
  arduboy.clear();
  //Game code here
  arduboy.display();
}

Notice that I added some comments at the top for the project as well as some placeholders. Up until now, this is usually how we started each project, but let’s add a little more to this to give us a better starting point for any future projects.

Frame Rates

Most game consoles can play games at 30 or 60 frames per second. That means that the screen is updated 30 or 60 times a second. The more instructions that a computer has to run in a second, the slower that framerate can be. If the frame rate is too slow, some games are unplayable. Have you ever played a game and it played so slowly that it wasn’t fun anymore?

During the setup() function, we can declare what framerate we want our Arduboy game to be using the arduboy.setFrameRate() function. To make the Arduboy game run at 60 frames per second, include this line of code.

arduboy.setFrameRate(60);

A game slowing down can ruin the gameplay experience, but if a game runs too fast, that can be bad, too! We want the game to run at a consistant framerate. In order to do that, add this to the beginning of the loop() function.

if (!arduboy.nextFrame()) {
  return;
}

This isn’t really important, but what this does is check if it’s too early to display the next frame. If it is, the Arduboy will loop again until it’s ready. Pretty much making sure that everything runs as smoothly as possible.

You’re ready!

During the setup() function, we also want to seed the random number generator so that we can grab some random numbers later. Include the srand(7/8); to your setup() function.

Okay! You should be ready! Here’s the code that you should be able to use at the start of all your projects!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;

//Variables declared here

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {
  
  //Prevent the Arduboy from running too fast
  if (!arduboy.nextFrame()) {
    return;
  }

  arduboy.clear();
  //Game code here
  arduboy.display();
}

2. Structuring The Game

We need to set up a title screen for our game as well as a win and game over screen. We also need a section for our gameplay. These will be called game states. Let’s create a variable to keep track of the game state as well as use the switch keyword to set up different blocks of code for each state.

Let’s start by declaring a variable called gamestate .

int gamestate = 0;

In the area of the loop() for the game code , let’s add the switch and check the value of gamestate .

switch (gamestate) {

}

If gamestate is 0, we want the title screen. If it’s 1, we want the gameplay state. If it’s 2 or 3, then we’ll show a win screen or a game over screen. Let’s set up those cases:

switch (gamestate) {

  case 0:
    //Title screen
    break;

  case 1:
    //Gameplay screen
    break;

  case 2:
    //Win screen
    break;

  case 3:
    //Game over screen
    break;
}

Let’s also add text so that we can test this.

switch (gamestate) {

  case 0:
    //Title screen
    arduboy.setCursor(0, 0);
    arduboy.print("Title Screen");
    break;

  case 1:
    //Gameplay screen
    arduboy.setCursor(0, 0);
    arduboy.print("Gameplay");
    break;

  case 2:
    //Win screen
    arduboy.setCursor(0, 0);
    arduboy.print("Win Screen");
    break;

  case 3:
    //Game over screen
    arduboy.setCursor(0, 0);
    arduboy.print("Game Over Screen");
    break;
}

Here’s the code so far! Test it out and see how it works!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;

//Variables declared here

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {
  
  //Prevent the Arduboy from running too fast
  if (!arduboy.nextFrame()) {
    return;
  }

  arduboy.clear();
  
  switch (gamestate) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      break;

    case 1:
      //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      break;

    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen");
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      break;
  }

  arduboy.display();
}

So, the title screen appears, but nothing else works. Let’s add the ability to go to different screens when you push the A button.

Inside of each case , let’s check if the A button is pressed, and if it is, then change the value of gamestate . Usually, we’ll increase gamestate by 1, but during the last case , we’ll set it back to 0 in order to cycle through all of the screens.

switch (gamestate) {

  case 0:
    //Title screen
    arduboy.setCursor(0, 0);
    arduboy.print("Title Screen");
    if (arduboy.justPressed(A_BUTTON)) {
      gamestate = 1;
    }
    break;

  case 1:
    //Gameplay screen
    arduboy.setCursor(0, 0);
    arduboy.print("Gameplay");
    if (arduboy.justPressed(A_BUTTON)) {
      gamestate = 2;
    }
    break;

  case 2:
    //Win screen
    arduboy.setCursor(0, 0);
    arduboy.print("Win Screen");
    if (arduboy.justPressed(A_BUTTON)) {
      gamestate = 3;
    }
    break;

  case 3:
    //Game over screen
    arduboy.setCursor(0, 0);
    arduboy.print("Game Over Screen");
    if (arduboy.pressed(A_BUTTON)) {
      gamestate = 0;
    }
    break;
}

Okay, let’s run the completed code to test it!

3. Bouncing Ball

Alright, let’s create the ball for this game. It’ll bounce around the screen. If it hits the top, bottom, or sides of the screen, it’ll change direction.

We’ll need to declare variables for the ball’s location as well as the ball’s size.

int ballx = 62;
int bally = 0;
int ballsize = 4;

We’ll also create one for the vertical and one for the horizontal direction of on the screen.

int ballright = 1;
int balldown = 1;

Whenever ballright is 1, we’ll move the ball to the right. If ballright is -1, we’ll move the ball to the left. Likewise, when balldown is 1, we’ll move the ball down. When balldown is -1, we’ll move the ball up.

Inside of the gameplay case, we’ll start by drawing the ball using the arduboy.fillRect() function. Add this line:

arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);

Next, let’s handle the movement of the ball horizontally by changing the value of ballx .

if (ballright == 1) {
  ballx = ballx + 1;
}
if (ballright == -1) {
  ballx = ballx - 1;
}

Whenever ballx is at the left or right edge of the screen, we’ll change the value of ballright . Where are the left and right edges of the screen? Well, the Arduboy screen is 128 pixels wide, so if ballx is 0, the ball is on the left side of the screen. If ballx is 127, then it’s on the right side of the screen.

if (ballx == 0) {
  ballright = 1;
}
if (ballx == 127) {
  ballright = -1;
}

This is what your code should look like. Give it a test and see the ball bounce from side to side!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }
      //Reflect the ball off of the left side of the screen
      if(ballx == 0) {
        ballright = 1;
      }
      //Reflect the ball off of the right side of the screen
      if(ballx == 127) {
        ballright = -1;
      }
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

Cool! Let’s add vertical movement! It’s pretty much the exact same thing that we did with the ballright variable.

When balldown is 1, we’ll add 1 to bally . When balldown is -1, we’ll subtract 1 from bally .

if (balldown == 1) {
  bally = bally + 1;
}
if (balldown == -1) {
  bally = bally - 1;
}

Of course, we’ll also have to reflect it off of the top and bottom of the screen, right? The Arduboy’s screen is 64 pixels high, so let’s add this code:

if (bally == 0) {
  balldown = 1;
}
if (bally == 63) {
  balldown = -1;
}

That makes sense, right? Good! Here’s all the code we have so far! Let’s test it out!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }
      //Reflect the ball off of the left side of the screen
      if(ballx == 0) {
        ballright = 1;
      }
      //Reflect the ball off of the right side of the screen
      if(ballx == 127) {
        ballright = -1;
      }
      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally == 63) {
        balldown = -1;
      }

      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

There’s one more little tiny thing I want use to change before moving on. If you watch the ball carefully as it moves, you’ll notice that it moves off of the screen on the bottom and right-side.

The reason it does that is because we change the ball’s vertical direction based on the top of the ball hitting the top of the screen or the top of the ball hitting the bottom of the screen as well as checking if the left-side of the ball hits the left-side of the screen or the left-side of the ball hitting the right-side of the screen.

We need to make sure the bottom of the ball bounces against the bottom of the screen and make sure the right-side of the ball bounces off of the right-side of the screen. This is an easy adjustment.

Instead of checking if ballx is equal to 127, we need to check if ballx + ballsize is equal to 127. Same for bally .

Change the reflection cod to…

if (ballx + ballsize == 127) {
  ballright = -1;
}

… and…

if (bally + ballsize == 63) {
  balldown = -1;
}

Run the code on your Arduboy! Mesmorizing, isn’t it?

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }
      //Reflect the ball off of the left side of the screen
      if(ballx == 0) {
        ballright = 1;
      }
      //Reflect the ball off of the right side of the screen
      if(ballx + ballsize == 127) {
        ballright = -1;
      }
      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }

      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}
1 Like

4. Creating Your Paddle

This part is my favorite part since it really gives you control over the game. We’re going to make your paddle that you can move with the Up and Down buttons!

In the variable section, let’s declare these variables… These should be self-explanatory.

int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;

Back inside of the gameplay section, let’s draw the paddle, then allow it to be moved.

arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);

Next, let’s add some code to change the value of playery with the Up and Down buttons. Luckily, we don’t need to worry about coding any buffers for this since we want to be able to hold down the button for movement.

if (arduboy.pressed(UP_BUTTON)) {
  playery = playery - 1;
}
if (arduboy.pressed(DOWN_BUTTON)) {
  playery = playery + 1;
}

You probably could have figured that part out, but what if we only want to allow a player to move their paddle if they have room to move their paddle? We need to use the and keyword.

  • If the player presses the Up button and the top of the paddle ( playery ) is greater than ( > ) the top of the screen ( 0 ), then allow them to change the value of playery .
  • If the player presses the Down button and the bottom of the paddle ( playery + paddheight ) is less than ( < ) the bottom of the screen ( 127 ), then allow them to change the value of playery .
if (arduboy.pressed(UP_BUTTON) and playery > 0) {
  playery = playery - 1;
}
if (arduboy.pressed(DOWN_BUTTON) and playery + paddheight< 63) {
  playery = playery + 1;
}

In the above example, I have used the keyword ‘and’ keyword. This works in the Arduboy environment but in C++ (the language that this tutorial is teaching) the ‘and’ keyword is actually specified as ‘&&’. When you are viewing others code you will see this regularly so it’s best to get familiar with it. BTW, the ‘or’ command is represented as ‘||’.

So using the ‘&&’ keyword …

if (arduboy.pressed(UP_BUTTON) && playery > 0) {
  playery = playery - 1;
}
if (arduboy.pressed(DOWN_BUTTON) && playery + paddheight < 63) {
  playery = playery + 1;
}

That was relatively simple, right? Okay, here’s the code you should end up with. Let’s run it and test moving your paddle around!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }
      //Reflect the ball off of the left side of the screen
      if(ballx == 0) {
        ballright = 1;
      }
      //Reflect the ball off of the right side of the screen
      if(ballx + ballsize == 127) {
        ballright = -1;
      }
      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }

      //Draw the player's paddle
      arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
      //If the player presses Up and the paddle is not touching the top of the screen, move the paddle up
      if (arduboy.pressed(UP_BUTTON) && playery > 0) {
        playery = playery - 1;
      }
      //If the player presses down and the paddle is not touching the bottom of the screen, move the paddle down
      if (arduboy.pressed(DOWN_BUTTON) && playery + paddleheight < 63) {
        playery = playery + 1;
      }

      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

5. Creating The Computer Paddle

Creating the computer’s paddle will be very similar to ours, except instead of moving the paddle with buttons, the paddle will move based on the position of the ball.

Let’s add these variables near the top of the sketch for the computer paddle:

int computery = 0;
int computerx = 127 - paddlewidth;

Notice that I set the computer’s paddle all the way to the right-side of the screen, then move it over a few pixels to fit it onto the screen. :slight_smile:

Down in the gameplay part of the code, let’s draw the computer’s paddle.

arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);

Great! Now, we need to set the rules for when the computer’s paddle moves. We can adjust the AI later, but for now, if the top of the ball ( ballx ) is higher than the computer’s paddle’s top ( computery ), then the computer’s paddle should move up. If the bottom of the ball ( bally + ballsize ) is lower than the computer’s paddle’s bottom ( computery + paddleheight ), then we need to move the comptuer’s paddle down.

In code form, it would look like this:

if (bally < computery) {
  computery = computery - 1;
}
if (bally + ballsize > computery + paddleheight) {
  computery = computery + 1;
}

Cool! :sunglasses: That was actually pretty easy! Run the code!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;
int computery = 0;
int computerx = 127 - paddlewidth;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }
      //Reflect the ball off of the left side of the screen
      if(ballx == 0) {
        ballright = 1;
      }
      //Reflect the ball off of the right side of the screen
      if(ballx + ballsize == 127) {
        ballright = -1;
      }
      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }

      //Draw the player's paddle
      arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
      //If the player presses Up and the paddle is not touching the top of the screen, move the paddle up
      if (arduboy.pressed(UP_BUTTON) && playery > 0) {
        playery = playery - 1;
      }
      //If the player presses down and the paddle is not touching the bottom of the screen, move the paddle down
      if (arduboy.pressed(DOWN_BUTTON) && playery + paddleheight < 63) {
        playery = playery + 1;
      }
      
      //Draw the computer's paddle
      arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);
      //If the ball is higher than the computer's paddle, move the computer's paddle up
      if(bally < computery) {
        computery = computery - 1;
      }
      //If the bottom of the ball is lower than the bottom of the computer's paddle, move the comptuer's paddle down
      if(bally + ballsize > computery + paddleheight) {
        computery = computery + 1;
      }

      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

Notice how good the AI is. The computer’s paddle will never miss! It’s too good! Don’t worry! We’ll adjust it later to make it possible to beat. :slight_smile:

6. Collision Checking

What we need to do next is change the ball up some. Instead of bouncing against the right and left side of the screen, we need to make it bounce off of the paddles instead. Once we get the ball bouncing off of the paddles, we’ll remove the original bouncing code!

Okay! Let’s begin by talking about when the ball will bounce off of the paddle. If the ball is higher than the paddle or lower than the paddle, then it will not bounce. If the ball is near the top, bottom, or middle of the paddle, then we’ll change it’s direction to bounce it back. Take a look at this beautiful masterpiece I drew for you to help illustrate this. :art:

Let’s look at the code for the ball hitting the left side of the screen.

if (ballx == 0) {
  ballright = 1;
}

Instead of checking if the ball’s left side ( ballx ) hits the edge of the screen, we need to do our check where the ball’s left side ( ballx ) hits the player’s paddle on the right side. The player’s paddle’s right is is going to be at playerx + paddlewidth .

We now have:

if (ballx == playerx + paddlewidth) {
  ballright = 1;
}

So, now that we know where we need to check along the X-axis, where do we check along the Y-axis?

Well, the paddle will make contact if the top of the paddle ( playery ) is higher on the screen than the bottom of the ball ( bally + ballsize ). Not only that, but the bottom of the paddle ( playery + paddleheight ) has to be lower on the screen than the top of the ball ( bally ).

if (ballx == playerx + paddlewidth && playery < bally + ballsize && playery + paddleheight > bally) {
  ballright = 1;
}

For the computer’s paddle, we need to offset ballx by ballsize since we are checking the right-side of the ball. Here’s what it would look like:

if (ballx + ballsize == computerx && computery < bally + ballsize && computery + paddleheight > bally) {
  ballright = -1;
}

That’s it! We’re sooo close to being done with this game! Here’s the code we have so far, but go ahead and test it out!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;
int computery = 0;
int computerx = 127 - paddlewidth;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
       //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }
      //Reflect the ball off of the left side of the screen
      if(ballx == 0) {
        ballright = 1;
      }
      //Reflect the ball off of the right side of the screen
      if(ballx + ballsize == 127) {
        ballright = -1;
      }
      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }
      //Draw the player's paddle
      arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
      //If the player presses Up and the paddle is not touching the top of the screen, move the paddle up
      if(arduboy.pressed(UP_BUTTON) && playery > 0) {
        playery = playery - 1;
      }
      //If the player presses down and the paddle is not touching the bottom of the screen, move the paddle down
      if(arduboy.pressed(DOWN_BUTTON) && playery + paddleheight < 63) {
        playery = playery + 1;
      }
      //Draw the computer's paddle
      arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);
      //If the ball is higher than the computer's paddle, move the computer's paddle up
      if (bally < computery) {
        computery = computery - 1;
      }
      //If the bottom of the ball is lower than the bottom of the computer's paddle, move the comptuer's paddle down
      if (bally + ballsize > computery + paddleheight) {
        computery = computery + 1;
      }
      //If the ball makes contact with the player's paddle, bounce it back to the right
      if( ballx == playerx + paddlewidth && playery < bally + ballsize && playery + paddleheight > bally) {
        ballright = 1;
      }
      //If the ball makes contact with the computer's paddle, bounce it back to the left
      if (ballx + ballsize == computerx && computery < bally + ballsize && computery + paddleheight > bally) {
        ballright = -1;
      }
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}
1 Like

Or Operator

We already talked about using the and operator. It’s a way we connect two comparisons inside of an if statement. To illustrate it, look at this code:

if (a == 5 && b > 20 ) {
  c = 0;
}

c will only be set to 0 if a is equal to 5 and b is greater than 20 .

There are some other operators that we can use instead of the and operator. One of them is the or operator. The or operator can be used to check if one of a few comparisons are true. Check out this code:

if (a == 5 || b > 20 ) {
  c = 20;
}

In the above example, c will be set to 20 if either a is equal to 5 or b is greater than 20 .

Keep the or operator in mind. We’ll use it soon!

7. Adjusting The AI

Okay, so, the computer player is way too good. We’ll never be able to win. One thing we can do to stop it from being so good is to only allow it to move some of the time. When will we allow it to move its paddle? Well, for starters, we could let it move its paddle only whenever the ball is close to the right side of the screen!

Find these lines of code:

if (bally < computery) {
  computery = computery - 1;
}
if (bally + ballsize > computery + paddleheight) {
  computery = computery + 1;
}

These are the lines of code that move the computer’s paddle. Let’s put an if statement around them that checks if the ball’s horizontal position ( ballx ) is close to the right-side of the screen. I put 115.

if (ballx > 115) {
  if(bally < computery) {
    computery = computery - 1;
  }
  if(bally + ballsize > computery + paddleheight) {
    computery = computery + 1;
  }
}

Test it out and think about it for a second. Notice how the computer’s paddle doesn’t always move like it used it? It’s a little more precise right now, but only moves whenever the ball is close to scoring.

But, we need to add more variance… More randomness… We need to make it so that the game is different every time you play. I KNOW! Let’s let the computer paddle move when the ball is close or let the computer paddle move when the computer picks a random number.

Back in Part 5 of this series, I showed you how to pick a random number. The line below shows how to select a random number between 0 and 19 - you might recall that the two parameters specify the lower range (inclusive) and the upper range (exclusive).

random(0, 20)

Let’s adjust that if statement from above!

if (ballx > 115 || random(0, 20) == 1) {

This means that if ballx is greater than 115, or a randomly-picked number is equal to 1, then we move the computer’s paddle. Basically, the computer’s paddle will randomly move 1/20th of the time.

Here’s the full code so far!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;
int computery = 0;
int computerx = 127 - paddlewidth;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
       //Gameplay screen
      arduboy.setCursor(0, 0);
      arduboy.print("Gameplay");
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }
      //Reflect the ball off of the left side of the screen
      if(ballx == 0) {
        ballright = 1;
      }
      //Reflect the ball off of the right side of the screen
      if(ballx + ballsize == 127) {
        ballright = -1;
      }
      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }
      //Draw the player's paddle
      arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
      //If the player presses Up and the paddle is not touching the top of the screen, move the paddle up
      if(arduboy.pressed(UP_BUTTON) && playery > 0) {
        playery = playery - 1;
      }
      //If the player presses down and the paddle is not touching the bottom of the screen, move the paddle down
      if(arduboy.pressed(DOWN_BUTTON) && playery + paddleheight < 63) {
        playery = playery + 1;
      }
      //Draw the computer's paddle
      arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);
      //If the ball is higher than the computer's paddle, move the computer's paddle up
      if (ballx > 115 || random(0, 20) == 1) {
        if (bally < computery) {
          computery = computery - 1;
        }
        //If the bottom of the ball is lower than the bottom of the computer's paddle, move the comptuer's paddle down
        if (bally + ballsize > computery + paddleheight) {
          computery = computery + 1;
        }
      }
      //If the ball makes contact with the player's paddle, bounce it back to the right
      if (ballx == playerx + paddlewidth && playery < bally + ballsize && playery + paddleheight > bally) {
        ballright = 1;
      }
      //If the ball makes contact with the computer's paddle, bounce it back to the left
      if (ballx + ballsize == computerx && computery < bally + ballsize && computery + paddleheight > bally) {
        ballright = -1;
      }
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

8. Scoring

Since we’re going to introduce scoring, we need a way for the ball to actually be scored. This means we need to remove some of our old bouncing code.

if (ballx == 0) {
  ballright = 1;
}
if (ballx + ballsize == 127) {
  ballright = -1;
}

Find those lines and remove them. This way, the ball will continue to move beyond the screen. In fact, we’ll check to see if the ball has moved off of the screen in order to give points!

Feel free to test the code out once you remove that code. :laughing:

To keep track of the scores, let’s declare some variables at the top of the sketch.

int playerscore = 0;
int computerscore = 0;

Now, look for the code in case 1 that displayed the text, “Gameplay.” Instead of just displaying that text, let’s modify it to display the player’s and computer’s scores.

arduboy.setCursor(20, 0);
arduboy.print(playerscore);

arduboy.setCursor(101, 0);
arduboy.print(computerscore);

Next, we need a way to actually score! Since the code now allows for the ball to move off of the screen, let’s check if it’s off the screen and if it is, then give someone a point, and then move it back into the middle of the screen.

Here’s how we can check if the ball is off of the screen.

if (ballx < -10) {

}
if (ballx > 130) {

}

To change the points, and put it back into the middle of the screen, we simply change the appropriate variables…

if (ballx < -10) {
  ballx = 63;
  computerscore = computerscore + 1;
}
if (ballx > 130) {
  ballx = 63;
  playerscore = playerscore + 1;
}

I really suggest testing the game out, so far. Here’s the code that I have:

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;
int computery = 0;
int computerx = 127 - paddlewidth;
int playerscore = 0;
int computerscore = 0;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      //Display the player's score
      arduboy.setCursor(20, 0);
      arduboy.print(playerscore);
      //Display the computer's score
      arduboy.setCursor(101, 0);
      arduboy.print(computerscore);
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }

      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }
      //Draw the player's paddle
      arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
      //If the player presses Up and the paddle is not touching the top of the screen, move the paddle up
      if(arduboy.pressed(UP_BUTTON) && playery > 0) {
        playery = playery - 1;
      }
      //If the player presses down and the paddle is not touching the bottom of the screen, move the paddle down
      if(arduboy.pressed(DOWN_BUTTON) && playery + paddleheight < 63) {
        playery = playery + 1;
      }
      //Draw the computer's paddle
      arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);
      //If the ball is higher than the computer's paddle, move the computer's paddle up
      if (ballx > 115 || random(0, 20) == 1) {
        if (bally < computery) {
          computery = computery - 1;
        }
        //If the bottom of the ball is lower than the bottom of the computer's paddle, move the comptuer's paddle down
        if (bally + ballsize > computery + paddleheight) {
          computery = computery + 1;
        }
      }
      //If the ball moves off of the screen to the left...
      if(ballx < -10) {
        //Move the ball back to the middle of the screen
        ballx = 63;
        //Give the computer a point
        computerscore = computerscore + 1;
      }
      //If the ball moves off of the screen to the right....
      if(ballx > 130) {
        //Move the ball back to the middle of the screen
        ballx = 63;
        //Give the player a point
        playerscore = playerscore + 1;
      }
      //If the ball makes contact with the player's paddle, bounce it back to the right
      if (ballx == playerx + paddlewidth && playery < bally + ballsize && playery + paddleheight > bally) {
        ballright = 1;
      }
      //If the ball makes contact with the computer's paddle, bounce it back to the left
      if (ballx + ballsize == computerx && computery < bally + ballsize && computery + paddleheight > bally) {
        ballright = -1;
      }
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 3;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

Awesome, huh? It’s pretty much a finished game at this point! We just need to clean it up, some!

One thing we need to do is check if someone wins! Let’s do a check to see if someone has 5 points. If they do, then change the gamestate variable to the appropriate value.

if (playerscore == 5) {
  gamestate = 2;
}
if (computerscore == 5) {
  gamestate = 3;
}

Hmm… Maybe we should change the code inside of case 2 for pushing the A button. Instead of taking you to gamestate = 3 , maybe we should use gamestate = 0 so that it takes you to the title screen of the game. Why would we want to show the win screen, then game over screen right afterwards, right?

Here’s the completed code so far:

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;
int computery = 0;
int computerx = 127 - paddlewidth;
int playerscore = 0;
int computerscore = 0;

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      //Display the player's score
      arduboy.setCursor(20, 0);
      arduboy.print(playerscore);
      //Display the computer's score
      arduboy.setCursor(101, 0);
      arduboy.print(computerscore);
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }

      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }
      //Draw the player's paddle
      arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
      //If the player presses Up and the paddle is not touching the top of the screen, move the paddle up
      if(arduboy.pressed(UP_BUTTON) && playery > 0) {
        playery = playery - 1;
      }
      //If the player presses down and the paddle is not touching the bottom of the screen, move the paddle down
      if(arduboy.pressed(DOWN_BUTTON) && playery + paddleheight < 63) {
        playery = playery + 1;
      }
      //Draw the computer's paddle
      arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);
      //If the ball is higher than the computer's paddle, move the computer's paddle up
      if (ballx > 115 || random(0, 20) == 1) {
        if (bally < computery) {
          computery = computery - 1;
        }
        //If the bottom of the ball is lower than the bottom of the computer's paddle, move the comptuer's paddle down
        if (bally + ballsize > computery + paddleheight) {
          computery = computery + 1;
        }
      }
      //If the ball moves off of the screen to the left...
      if(ballx < -10) {
        //Move the ball back to the middle of the screen
        ballx = 63;
        //Give the computer a point
        computerscore = computerscore + 1;
      }
      //If the ball moves off of the screen to the right....
      if(ballx > 130) {
        //Move the ball back to the middle of the screen
        ballx = 63;
        //Give the player a point
        playerscore = playerscore + 1;
      }

      //Check if the player wins
      if(playerscore == 5) {
        gamestate = 2;
      }
      //Check if the computer wins
      if(computerscore == 5) {
        gamestate = 3;
      }

      //If the ball makes contact with the player's paddle, bounce it back to the right
      if (ballx == playerx + paddlewidth && playery < bally + ballsize && playery + paddleheight > bally) {
        ballright = 1;
      }
      //If the ball makes contact with the computer's paddle, bounce it back to the left
      if (ballx + ballsize == computerx && computery < bally + ballsize && computery + paddleheight > bally) {
        ballright = -1;
      }
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

9. Reset Function

If you tested this out, you’re going to notice that once you win and try to play again, you won’t really be able to. The reason this happens is that the Arduboy remembers the score from the last match! It starts the new match of Pong, checks the scores, and realizes someone has already won, then shows you either the win screen or game over screen.

What we need to do is reset the game’s variables… ballx , playerscore , and computerscore .

Scroll all the way down to case 2 and case 3 . Inside of both of them, there’s a check to see if we push the A button. This is a great place to put the code to reset our variables since pushing A is supposed to reset the game to the very beginning.

So, inside of the button checks of case 2 and case 3 , put this code:

ballx = 63;
playerscore = 0;
computerscore = 0;

Actually! I got an idea! Instead of writing the same code multiple times, I should teach you about writing functions to save you time!

You already kinda know what functions are, right? They’re instructions that the computer follows. One example of this is arduboy.clear() , which will erase everything on the screen!

Well, one cool thing about programming is that you can write your own functions! It’s really helpful! Sometimes, you’ll have code that you want to use over and over again, but maybe you don’t want to type over and over again…

Scroll all the way up… After you declare your variables, let’s declare a function. :heart: We’ll call it resetgame() . Type this out:

void resetgame() {

}

Inside of the braces, we’ll be able to put the instructions that are contained within the resetgame() function. Let’s update it with the code we used a moment ago!

void resetgame() {
  ballx = 63;
  playerscore = 0;
  computerscore = 0;
}

There we go! Any time we want to run those instructions, instead of typing out all 3 of those lines, we can save time by typing resetgame() instead!

Back down near the bottom, add the resetgame() function where you change gamestate to 0! :slight_smile:

If you got confused, here’s the full code!

//Jonathan Holmes (crait)
//December 7th, 2016
//A simple Pong clone

#include <Arduboy2.h>
Arduboy2 arduboy;
 
//Variables declared here
int gamestate = 0;
int ballx = 62;
int bally = 0;
int ballsize = 4;
int ballright = 1;
int balldown = 1;
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;
int computery = 0;
int computerx = 127 - paddlewidth;
int playerscore = 0;
int computerscore = 0;

void resetGame() {
  ballx = 63;
  playerscore = 0;
  computerscore = 0;
}

void setup() {
  arduboy.begin();
  //Seed the random number generator
  arduboy.initRandomSeed();
  //Set the game to 60 frames per second
  arduboy.setFrameRate(60);
  arduboy.clear();
}

void loop() {

  //Prevent the Arduboy from running too fast
  if(!arduboy.nextFrame()) {
    return;
  }
  arduboy.clear();
  arduboy.pollButtons();

  //Game code here
  switch( gamestate ) {

    case 0:
      //Title screen
      arduboy.setCursor(0, 0);
      arduboy.print("Title Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 1;
      }
      break;

    case 1:
      //Gameplay screen
      //Display the player's score
      arduboy.setCursor(20, 0);
      arduboy.print(playerscore);
      //Display the computer's score
      arduboy.setCursor(101, 0);
      arduboy.print(computerscore);
      //Draw the ball
      arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE);
      //Move the ball right
      if(ballright == 1) {
        ballx = ballx + 1;
      }
      //Move the ball left
      if(ballright == -1) {
        ballx = ballx - 1;
      }

      //Move the ball down
      if(balldown == 1) {
        bally = bally + 1;
      }
      //Move the ball up
      if(balldown == -1) {
        bally = bally - 1;
      }
      //Reflect the ball off of the top of the screen
      if(bally == 0) {
        balldown = 1;
      }
      //Reflect the ball off of the bottom of the screen
      if(bally + ballsize == 63) {
        balldown = -1;
      }
      //Draw the player's paddle
      arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
      //If the player presses Up and the paddle is not touching the top of the screen, move the paddle up
      if(arduboy.pressed(UP_BUTTON) && playery > 0) {
        playery = playery - 1;
      }
      //If the player presses down and the paddle is not touching the bottom of the screen, move the paddle down
      if(arduboy.pressed(DOWN_BUTTON) && playery + paddleheight < 63) {
        playery = playery + 1;
      }
      //Draw the computer's paddle
      arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);
      //If the ball is higher than the computer's paddle, move the computer's paddle up
      if (ballx > 115 || random(0, 20) == 1) {
        if (bally < computery) {
          computery = computery - 1;
        }
        //If the bottom of the ball is lower than the bottom of the computer's paddle, move the comptuer's paddle down
        if (bally + ballsize > computery + paddleheight) {
          computery = computery + 1;
        }
      }
      //If the ball moves off of the screen to the left...
      if(ballx < -10) {
        //Move the ball back to the middle of the screen
        ballx = 63;
        //Give the computer a point
        computerscore = computerscore + 1;
      }
      //If the ball moves off of the screen to the right....
      if(ballx > 130) {
        //Move the ball back to the middle of the screen
        ballx = 63;
        //Give the player a point
        playerscore = playerscore + 1;
      }

      //Check if the player wins
      if(playerscore == 5) {
        gamestate = 2;
      }
      //Check if the computer wins
      if(computerscore == 5) {
        gamestate = 3;
      }

      //If the ball makes contact with the player's paddle, bounce it back to the right
      if (ballx == playerx + paddlewidth && playery < bally + ballsize && playery + paddleheight > bally) {
        ballright = 1;
      }
      //If the ball makes contact with the computer's paddle, bounce it back to the left
      if (ballx + ballsize == computerx && computery < bally + ballsize && computery + paddleheight > bally) {
        ballright = -1;
      }
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        gamestate = 2;
      }
      break;
 
    case 2:
      //Win screen
      arduboy.setCursor(0, 0);
      arduboy.print("Win Screen"); 
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        resetGame();
        gamestate = 0;
      }
      break;

    case 3:
      //Game over screen
      arduboy.setCursor(0, 0);
      arduboy.print("Game Over Screen");
      //Change the gamestate
      if (arduboy.justPressed(A_BUTTON)) {
        resetGame();
        gamestate = 0;
      }
      break;
  }

  arduboy.display();
}

Wow!

Give yourself a pat on the back! Good job with this one! It was a long tutorial, but if you made it this far, you really deserve some kind of prize! :slight_smile: You are definitely ready to start experimenting and making your own game!

Next Tutorial

In the next tutorial, we start a HUGE game called DinoSmasher! Check it out, here: PART 8

Credits

I wrote this tutorial in order to give back to the programming community that taught me to get into it about 10 years ago. If you’d like to follow me on Twitter, please do so at http://www.twitter.com/crait . I’d greatly appreciate that. :smile:

2 Likes

This was so helpful to someone totally new to Arduboy like me! I really learned somthing:D Thank you so much!!!

3 Likes