This time, it is going to be a lot more dynamic. We are approaching a full game!

Bouncing all over the place

Length 20 minutes

Level Complete beginner

Prerequisites

In the previous workshop, you made a tally counter. You learned to use variables of type int. We also looked at if statements and conditions to interact with the player. Finaly, we used a function to draw rectangles to the screen.

So in summary, you made a rectangle move by pressing buttons. So we are not far from having a Pong paddle ;)But a Pong game without a ball is not very fun. This is why we will now code a bouncing ball.

Moving Forward

For our bouncing ball, we would need a new variable called positionX, which, like you guessed, stores the X (or horizontal) position of our ball. While we are at it, let's add another variable called speedX which keeps track of the speed of our ball along the X axis.

Now, look at this code: it makes the ball move forward on it's own!

#include 

int positionX = 32;
int speedX = 1;

void setup() {
  gb.begin();

}

void loop() {
  while (!gb.update());
  gb.display.clear();

  positionX = positionX + speedX;

  gb.display.print("positionX: ");
  gb.display.print(positionX);
  gb.display.print("\nspeedX: ");
  gb.display.print(speedX);

  gb.display.fillRect(positionX, 32, 4, 4);
}

About the screen and rectangles

When you were taught coordinates, you probably saw something like this where the center is where X and Y are equal to zero, and that X and Y get bigger when you go to the up and to the right. But for screens, this isn't the case.


Coordinates on the Gamebuino META's screen, just like all other screens, have their origin in the upper left corner. Not only that, but the Y values get bigger when you move downwards (the X values grow when moving to the right, just like a regular graph).

This means that the opposite corner (bottom right) is at (gb.display.width() - 1, gb.display.height() - 1).

Now why did we subtract 1 to get the opposite corner? Well it has to do with the fact that the first pixel has a value of 0 on both axes. Let me put it this way: if you had a screen with only four pixels, and the the first pixel's coordinate was 0, what would be the coordinate of the forth (last) pixel?

Here you can easily see that the forth pixel has a coordinate of 3, not 4. Well the same thing happens with you console's screen! The rightmost pixel has an x coordinate equal to gb.display.width() - 1. And the same thing goes for the lowest pixel.

Note: the screen's size is 80 pixels wide by 64 pixels tall. You can check the width by doing gb.display.print(gb.display.width()); in your code. Or by counting ;). Also note that even if you know this, you should not use 80 instead of gb.display.width(), because it is less implicit and is a sort of light obfuscation.


While we are on the topic of screen and positioning, let's take a closer look at how the gb.display.drawRect() function works. First, here is its structure:

gb.display.drawRect(int x, int y, int width, int height);

Just like the screen, the X and y passed as parameters are the position of the top left corner of our rectangle. So, knowing this, the bottom right corner of the rectangle has a position of (x + width - 1, y + height - 1).

Now that this is clear, try to draw the ball higher up the screen. How about drawing the ball so that it is right above the bottom of the screen.

Keeping The Ball In View

Let's launch our little game and see what happens...Hey! the ball just flies off the screen! Well actually that's expected, as we did not use conditions to stop it. So it just keeps going, even off screen. In that case, how could we keep the ball inside of our screen? Well, let's take a look at this algorithm.

If the ball reaches the right edge
Then go left

If the ball reaches the left edge
Then go right

So there are a couple of things we must look at:

  • How do we make it so that the ball goes towards the left?
  • How do we detect the edge of the screen?

Now, before I give you the solution, try to figure it out. Here are a few hints:

Think about what speedX does. Play around with its value.

Coordinates on the screen range from 0 to gb.display.width(). A value of 0 coresponds to the leftmost pixel, and gb.display.width() is the rightmost pixel.

If you are still stuck, here's what we did:

#include 

int positionX = 32;
int speedX = 1;

void setup() {
  gb.begin();

}

void loop() {
  while (!gb.update());
  gb.display.clear();

  positionX = positionX + speedX;

  // If the ball reaches the left side of the screen
  if(positionX < 0){
    // Go right
    speedX = 1;
  }

  // If the ball reaches the right side of the screen
  if(positionX > gb.display.width()){
    // Go left
    speedX = -1;
  }

  gb.display.print("positionX: ");
  gb.display.print(positionX);
  gb.display.print("\nspeedX: ");
  gb.display.print(speedX);

  gb.display.fillRect(positionX, 32, 4, 4);
}

It's your turn!

If the ball only moves left and right, this is not going to be a very exiting Pong match :P Why not create positionY et speedY so that the ball can now move across the screen. But just like the left-right movement, you will need to detect the edge (with gb.display.height()) and keep the ball inside the screen. Go ahead and give it a go!

Make us proud on social networks with #gamebuino #bouncingball , we go through them all the time;)

Solution Example

If you are running out of ideas, or need a little guidance, take a look at what we wrote :)

#include 

 




int positionX = 32;
int speedX = 2;
int positionY = 32;
int speedY = 1;
int ballSize = 8;




void setup() {
  gb.begin();




}




void loop() {
  while (!gb.update());
  gb.display.clear();




  // Update horizontal position
  positionX = positionX + speedX;




  // If the ball reaches the left side of the screen
  if(positionX < 0){
    // Go right
    speedX = 1;
  }




  // If the ball reaches the right side of the screen
  if(positionX > gb.display.width() - ballSize){
    // Go left
    speedX = -1;
  }




  // Update vertical position
  positionY = positionY + speedY;




  // If the ball reaches the top side of the screen
  if(positionY < 0){
    // Go down
    speedY = 1;
  }




  // If the ball reaches the bottom side of the screen
  if(positionY > gb.display.height() - ballSize){
    // Go up
    speedY = -1;
  }




  gb.display.setColor(BROWN);
  gb.display.print("positionX: ");
  gb.display.print(positionX);
  gb.display.print("\nspeedX: ");
  gb.display.print(speedX);




  gb.display.print("\npositionY: ");
  gb.display.print(positionY);
  gb.display.print("\nspeedY: ");
  gb.display.print(speedY);




  gb.display.setColor(WHITE);
  gb.display.fillRect(positionX, positionY, ballSize, ballSize);
}



Next Workshop

By Aurélien Rodot, modified by Julien Giovinazzo

Any questions / comments / suggestions, be sure to drop a comment down below!

Last comments

Aurélien Rodot

NEW 3 weeks ago

Juice_Lizard Juice_Lizard

Merci, c'est corrigé !

Juice_Lizard

NEW 3 weeks ago

Adamko Adamko

Il y a une petite erreur dans les commentaires: c'est écrit deux fois "si la balle atteint le bord gauche" (le second concerne le bord droit donc).

Aurélien Rodot

3 weeks ago

Merci, c'est corrigé !

qpd00z

NEW 3 months ago

@Adamko: You're right, but it would have been nice if you had concurrently given a solution. So, I do.

Fail: The ball is moving out of screen, when it reaches the right side of the the screen. 

Solution: We have to subtract the size of the ball. (like in case of bottom touch)

Bugfix: 

Change

// If the ball reaches the right side of the screen
if(positionX > gb.display.width()){

into

// If the ball reaches the right side of the screen
if(positionX > gb.display.width() - ballSize){

and everything works fine.

Greetz & have fun everybody 

qpd00z