06 Arduino How? Let’s Make the Paddle Bounce the Pong Ball

Date:  May 21, 2017

/* Notes:  If you want to read the previous 5 blog posts on how to make a Pong game on Arduino, you can just search “miniliew Arduino How” on either google or the Miniliew website */

In the last lesson, you manage to draw the paddle.  By turning the potentiometer, you are able to move the paddle.  And you notice, the paddle cannot bounce the ball because we have not implement the bouncing behaviour to the paddle yet.

This should be the last lesson for creating a Pong game using Arduino.

  • We will make the paddle to bounce the Pong Ball
  • We also will make a different sound if you miss bouncing the Pong Ball

IMG_0567.jpg

Let’s get started.

By now, you should have removed the right wall so that it does not bounce anything.

You also have already have a movable paddle that you can try to bounce the pong ball.

So, all you need to add in your Movement() code block is that, if the ballX position has > then your paddle surface (i.e. screen width 128 -1 – paddle’s width) and if the ballY falls between paddlePositionA & paddle PositionA + paddle’s height, then, you bounce the ball back by negating the ballMoveX (multiply by -1 so that it will start deducting the x-position).

if (ballX >= SCREEN_WIDTH - 1 - PADDLE_WIDTH - BALL_SIZE/2 && ballSpeedX > 0) {
  if (ballY >= paddlePositionA && ballY < paddlePositionA + PADDLE_HEIGHT) {
  ballMoveX *= -1;
  soundBounce();
  }
}

That will do the trick.

Now, what if the ballY is outside of the paddle, then, you will reset a ballX.   You don’t have to reset the ballY, so that it will always restart at the y-axis position when the ball last touch the paddle, make it seems like random.

So, you will need a routine to check that.

 // score point
 if (ballX >= SCREEN_WIDTH - 1 - BALL_SIZE/2) {
   if (ballSpeedX > 0) {
     scoreA++;
     ballX = 32; // only reset the x-axis, retain the y-axis
   }
   soundPoint();
 }
 //set last paddle locations
 lastPaddlePositionA = paddlePositionA;

Don’t forget to write a soundPoint() function which sound a different tone.

void soundPoint() 
{
 tone(BEEPER, NOTE_D3, 150);
}

That’s it.  As simple as it is.

So, now you got a working Pong game.

Very simple logic of programming.  Not hard at all.

And here are some of the improvement you might want to do.

  • Print scores
  • add effect if you hit the ball while paddle is moving, sound a different sound, add speed, or slow down like a slide ball, etc.
  • You can try to program an AI (Artificial Intelligent) that means you will need to remove another wall and add Paddle B.
  • You can add another potentiometer so that you can have two player games.
  • You can make it into a Squash game too.
  • Or you make it to 4-paddle Hockey game.

So, it is up to you what you want to design.  I ported a Pong game from the Internet and I quite like it.  Take a look.  I actually ported the source code to make it run on my DIYMall 0.96″ OLED, and I also make use of the multiple digital pin to change the game mode to Single player mode (Vs. AI) or Two players mode, and I can change it to play either the Pong game, Hockey game or the Squash game.  This is how coding add some spices into my life.  Check out this game.

The source code for today’s work is as follow.

#include <Arduino.h>
#include <U8g2lib.h>
#include "pitches.h"

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

#define BALL_SIZE 4
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define BEEPER 8 // connect the beeper to digital input pin #8

#define BALL_MOVEX 4 // when you move your pong ball, how far x-axis it should move from last position
#define BALL_MOVEY 2 // when you move your ping ball, how far y-axis it should move from last position

#define CONTROL_A A0 // Potentiometer reading the Analog pin A0
#define PADDLE_WIDTH 2
#define PADDLE_HEIGHT 20
#define PADDLE_PADDING 1

int controlA;
int paddlePositionA = 0;
int lastPaddlePositionA = 0;
int ballSpeedX = BALL_MOVEX;
int ballSpeedY = BALL_MOVEY;
int scoreA = 0;

int ballX = SCREEN_WIDTH/2; // start to "drop" the pong ball from center of x-axis
int ballY = BALL_SIZE/2+1; // start to "drop" the pong ball from top
int ballMoveX = BALL_MOVEX;
int ballMoveY = BALL_MOVEY;

void draw(void) {

 // draw playing area
 u8g2.drawVLine(0,0,64);
 u8g2.drawHLine(0,0,128);
 u8g2.drawHLine(0,63,128);

 // draw paddle
 u8g2.drawBox(SCREEN_WIDTH - 1 - PADDLE_WIDTH, paddlePositionA, PADDLE_WIDTH, PADDLE_HEIGHT);
 
 // draw ball
 u8g2.drawDisc(ballX,ballY,BALL_SIZE/2);

 u8g2.setFont(u8g2_font_helvB08_tf);
 u8g2.setCursor(20,45);
 u8g2.print(ballX);
 u8g2.setCursor(50,45);
 u8g2.print(ballY);
 
 u8g2.setFont(u8g2_font_helvB08_tf);
 u8g2.setCursor(20,30);
 u8g2.print(paddlePositionA);

 u8g2.setCursor(50,30);
 u8g2.print(controlA);
 
}

void Movement(){

 // Read the analog value from the potentiometer
 controlA = analogRead(CONTROL_A);

 // Map the analog range to the screen height minus the paddle's height
 // paddlePositionA is the starting y-axis of the paddle to be drawn
 paddlePositionA = map(controlA, 2, 680, 0, SCREEN_HEIGHT-PADDLE_HEIGHT);

 // If you minus the last postion and the new position of the tip of paddle, that will give you the paddle speed
 int paddleSpeedA = paddlePositionA - lastPaddlePositionA;


 // the pong ball move from last position in terms of x-axis and y-axis with these differnce
 ballX = ballX + ballMoveX;
 ballY = ballY + ballMoveY;

 // ball bouncing from top or bottom
 if (ballY >= SCREEN_HEIGHT - 3 - BALL_SIZE/2 || ballY <= 2 + BALL_SIZE/2) { 
 ballMoveY *= -1; // instead of adding, reverse the polarity, start to minus
 soundBounce();
 }

 // ball bouncing from left wall inly
 if (ballX <= 2 + BALL_SIZE/2) {
 ballMoveX *= -1; // instead of adding, revrse the polarity, start to minus
 soundBounce();
 }

 // ball boucing from the paddle
 // paddle currently is at the paddlePositionA, has length of PADDLE_WIDTH 
 // First, you check if the ball x-axis has passed the paddle surface, and 
 if (ballX >= SCREEN_WIDTH - 1 - PADDLE_WIDTH - BALL_SIZE/2 && ballSpeedX > 0) {
 // if the ball y-axis is within the range of the paddle height
 if (ballY >= paddlePositionA && ballY < paddlePositionA + PADDLE_HEIGHT) {
 ballMoveX *= -1;
 soundBounce();
 }
 }

 // score point
 if (ballX >= SCREEN_WIDTH - 1 - BALL_SIZE/2) {
 if (ballSpeedX > 0) {
 scoreA++;
 ballX = 32; // only reset the x-axis, retain the y-axis
 }
 soundPoint();
 }
 //set last paddle locations
 lastPaddlePositionA = paddlePositionA;
}

void soundBounce() 
{
 tone(BEEPER, NOTE_B4, 50);
}

void soundPoint() 
{
 tone(BEEPER, NOTE_D3, 150);
}


void setup(void) {
 u8g2.begin(); // initialise the display
}

void loop(void) {
 Movement();
 u8g2.firstPage();
 do {
 draw();
 } while (u8g2.nextPage());
 // delay(200); // for troubleshooting purpose, make the ball move slowly
}

IMG_0139.jpg

 

Leave a Reply