(7) Paddle and bouncing ball

If you take what is in the 5th and 6th post and put it all in the same program you will get a bouncing ball and a moving paddle. Let's do that. The code is (with some clean up):

// Run once at start
void setup() {
  // 500 pixels wide, 400 pixel height
  // This call will set system variables (width, height)
  size(500, 400);
  rectMode(CENTER);
}

// Variables to keep track of position and speed of ball
int x = 0;
int y = 100;
int x_speed = 5;
int y_speed = 5;
// Variables to keep track of paddle
int x_paddle = 250, y_paddle = 370;
int paddle_width_half = 40;

// Called every re-draw, defaul 30 times per second
void draw() {

  // Update position by adding speed
  x = x + x_speed;
  y = y + y_speed;
  if (y>height) 
    y_speed = -y_speed;
  else if (y<0)
    y_speed = -y_speed;
  if (x>width || x<0)  
    x_speed = -x_speed;

  // Check if keys are pressed
  if (keyPressed) {
    if (keyCode == RIGHT || key == 'd') {
      // Move paddle right
      x_paddle = x_paddle + 8;
    } else if (keyCode == LEFT || key == 'a') {
      // Move paddle left
      x_paddle = x_paddle - 8;
    }
  }
  // Check if paddle is at edge of screen 
  if (x_paddle>width) x_paddle = width;
  if (x_paddle<0) x_paddle = 0;

  // Clear screen to black
  background(0);
  // Set fill color to white
  fill(255);
  // Draw a circle at position x,y, 10 pixels large
  ellipse(x, y, 10, 10);
  // draw paddle
  rect(x_paddle, y_paddle, paddle_width_half*2+1, 11);
}

Try to copy it and run it. Almost a start of the breakout game, right? But that code does nothing when the ball hits the paddle and the ball does not disappear when it reaches the bottom of the screen. Let's try to fix that. Making it disappear at the bottom is simple. We just remove the check where we reverse the y_speed when it reaches the bottom. I.e. removing:

  if (y>height) 
    y_speed = -y_speed;

Will make the ball disappear at the bottom. How about making the ball "bounce" of the paddle? It is not as simple as what we just removed, as the paddle is smaller, and can move. We need to check if the ball is hitting where the paddle is at the moment. We need to check that 4 conditions are met at the same time. The ball needs to be in x-position where the paddle is (checked in the first two lines below) and then we also need to check that the paddle is in y-position where we have the paddle. We need to have a range here as the ball is travelling with some speed and will not move just one pixel at the time. Place this code just before the real drawing begins (i.e. at the background()):

  // Check if ball collides with paddle
  if ((x_paddle-paddle_width_half)<x && (x_paddle+paddle_width_half)>x && 
    (y_paddle-10)<y && (y_paddle)>y) {
    // ball is hitting paddle rectangle, reverse y_speed
    y_speed = -y_speed;
  }

Now try it and run it. You should be able to keep the ball bouncing if you have skills and precision for a while. What if we tried to add a score keeping for each bounce of the paddle you manage? Declare a global variable (done outside the setup() and draw() routines) called "score" like:

// score keeping
int score = 0;

And add an increment to the score inside the "if" where we detected the hit of the paddle:

  // Check if ball collides with paddle
  if ((x_paddle-paddle_width_half)<x && (x_paddle+paddle_width_half)>x && 
    (y_paddle-10)<y && (y_paddle)>y) {
    // ball is hitting paddle rectangle, reverse y_speed
    y_speed = -y_speed;
    score = score + 1;
  }

But how would we know the score? We need to display the score. This is done by:

  // Display score
  textSize(16);
  textAlign(RIGHT);
  text("Score", 80, 390);
  textAlign(LEFT);
  text(score, 90, 390);

Remember to put this after the "background()" call, since that is erasing the whole screen. So far we have this code, if you have followed along:

// Run once at start
void setup() {
  // 500 pixels wide, 400 pixel height
  // This call will set system variables (width, height)
  size(500, 400);
  rectMode(CENTER);
}

// Variables to keep track of position and speed of ball
int x = 0;
int y = 100;
int x_speed = 5;
int y_speed = 5;
// Variables to keep track of paddle
int x_paddle = 250, y_paddle = 370;
int paddle_width_half = 40;
// score keeping
int score = 0;

// Called every re-draw, default 30 times per second
void draw() {

  // Update position by adding speed
  x = x + x_speed;
  y = y + y_speed;
  if (y<0)
    y_speed = -y_speed;
  if (x>width || x<0)  
    x_speed = -x_speed;

  // Check if keys are pressed
  if (keyPressed) {
    if (keyCode == RIGHT || key == 'd') {
      // Move paddle right
      x_paddle = x_paddle + 8;
    } else if (keyCode == LEFT || key == 'a') {
      // Move paddle left
      x_paddle = x_paddle - 8;
    }
  }
  // Check if paddle is at edge of screen 
  if (x_paddle>width) x_paddle = width;
  if (x_paddle<0) x_paddle = 0;

  // Check if ball collides with paddle
  if ((x_paddle-paddle_width_half)<x && (x_paddle+paddle_width_half)>x && 
    (y_paddle-10)<y && (y_paddle)>y) {
    // ball is hitting paddle rectangle, reverse y_speed
    y_speed = -y_speed;
    score = score + 1;
  }

  // Clear screen to black
  background(0);
  // Set fill color to white
  fill(255);
  // Draw a circle at position x,y, 10 pixels large
  ellipse(x, y, 10, 10);
  // draw paddle
  rect(x_paddle, y_paddle, paddle_width_half*2+1, 11);
  // Display score
  textSize(16);
  textAlign(RIGHT);
  text("Score", 80, 390);
  textAlign(LEFT);
  text(score, 90, 390);
}

If you haven't followed along, copy and paste the whole thing and run it. Nice right? Almost a breakout game. Certainly a game, although simple. Now, what is missing is that we do not detect when you miss and declare "Game Over" and have a way to restart. This is fixed by adding two parts. One print at the very end, before the last "}" in the draw():

  if (y>height) {
    textSize(40);
    textAlign(CENTER);
    text("Game over", 250, 150);
  }

And then also inside the "keyPressed" "if" statement, adding another check for hitting the spacebar:

  // Check if keys are pressed
  if (keyPressed) {
    if (keyCode == RIGHT || key == 'd') {
      // Move paddle right
      x_paddle = x_paddle + 8;
    } else if (keyCode == LEFT || key == 'a') {
      // Move paddle left
      x_paddle = x_paddle - 8;
    } else if (key == ' ') {
      // Restart
      x = 0;
      y = 100;
      x_paddle = 250;
      score = 0;
    }
  }

This last check for ' ' will reset the ball position, paddle position, and score to what it started with. Add it and run it. Nice? That is indeed a real game. Not too fancy and one get bored quickly, but still, a game. This is how it looks like:


Full source code:

// Run once at start
void setup() {
  // 500 pixels wide, 400 pixel height
  // This call will set system variables (width, height)
  size(500, 400);
  rectMode(CENTER);
}

// Variables to keep track of position and speed of ball
int x = 0;
int y = 100;
int x_speed = 5;
int y_speed = 5;
// Variables to keep track of paddle
int x_paddle = 250, y_paddle = 370;
int paddle_width_half = 40;
// score keeping
int score = 0;

// Called every re-draw, defaul 30 times per second
void draw() {

  // Update position by adding speed
  x = x + x_speed;
  y = y + y_speed;
  if (y<0)
    y_speed = -y_speed;
  if (x>width || x<0)  
    x_speed = -x_speed;

  // Check if keys are pressed
  if (keyPressed) {
    if (keyCode == RIGHT || key == 'd') {
      // Move paddle right
      x_paddle = x_paddle + 8;
    } else if (keyCode == LEFT || key == 'a') {
      // Move paddle left
      x_paddle = x_paddle - 8;
    } else if (key == ' ') {
      // Restart
      x = 0;
      y = 100;
      x_paddle = 250;
      score = 0;
    }
  }
  // Check if paddle is at edge of screen 
  if (x_paddle>width) x_paddle = width;
  if (x_paddle<0) x_paddle = 0;

  // Check if ball collides with paddle
  if ((x_paddle-paddle_width_half)<x && (x_paddle+paddle_width_half)>x && 
    (y_paddle-10)<y && (y_paddle)>y) {
    // ball is hitting paddle rectangle, reverse y_speed
    y_speed = -y_speed;
    score = score + 1;
  }

  // Clear screen to black
  background(0);
  // Set fill color to white
  fill(255);
  // Draw a circle at position x,y, 10 pixels large
  ellipse(x, y, 10, 10);
  // draw paddle
  rect(x_paddle, y_paddle, paddle_width_half*2+1, 11);
  // Display score
  textSize(16);
  textAlign(RIGHT);
  text("Score", 80, 390);
  textAlign(LEFT);
  text(score, 90, 390);
  if (y>height) {
    textSize(40);
    textAlign(CENTER);
    text("Game over", 250, 150);
  }
}

No comments:

Post a Comment