03 Arduino How? First Pong Ball Bounced off Wall

Date:  May 19, 2017

Jay was having fun reading my blogs and learn how to hook up the DIYMall 0.96″ OLED to the Arduino, and he learned how to print text, draw box, draw circles etc.  Very fun.  How to blink a LED etc etc.

I just found out all my DIYMall 0.96″ OLED are yellow+blue colour.  It is a monochrome OLED with two colours.  You might buy single colour, or many colour or white colour.

IMG_0312.jpg

It is time to take it to the next step.

Remember, learning Arduino can be hard because of that “C programming”.  (There is actually other programming languages that you can use, such as Python or Scratch, but I don’t want him all these easy variety, in my opinion, he should learn the way how we learned back in those donkey years, learn the right way).

“C programming” can be a stopper.  So, the only way to make it work, make the child learning fun is to come up with fun projects for him to work on, to think about, to relate back to his Scratch programming and Lego Mindstorms programming.

IMG_0331.jpg

OK, let’s get to do more exciting stuff.  This week, we are going to learn

  • How to draw a ping pong ball on the screen.
  • How to animate the ping pong ball, so that it can move.
  • How to bounce the ping pong ball off the wall.
  • and of course, as a bonus, how to draw the wall.

Draw a Ping Pong ball & the Wall

First let’s understand how it works.  Then, you can scroll down to the bottom and copy and paste the code.

First, we need to decide what is the size of our ball?  In this example I make it 4 pixel.  After you successfully make the program work later, you can come back and play around with its size.  You can make it 10 for example for a big ball.

The SCREEN_WIDTH and SCREEN_HEIGHT is predefine as the screen of your OLED.  You might have guess why we want to have these two values because, next time, if you go buy a bigger screen, and you want to port your code to that bigger screen, you just have to change here.  So, it is a good practice to define a certain variables at the beginning, instead of hard code the number, i.e. 128 & 64, you make use of SCREEN_WIDTH & SCREEN_HEIGH variable, it makes your code more readable.

Take note that when you use a #define statement, you do not end the line with a semi-colon.  Because it is a definition statement.

Screen Shot 2017-05-19 at 7.25.18 AM.png

Now, let’s declare 2 variables.  one is the x-axis position of the ball, and the other one is y-axis position of the ball.  And let’s give them an initial value so that I put the ball at the top in the middle.

Screen Shot 2017-05-19 at 7.49.41 AM.png

So, in order to draw the wall, you use the drawFrame() function.  Give the starting position in x and y, and then give the width and height of the rectangle you wish to draw.

To draw the ping pong ball.  You use drawDisc() function.  Give it the center of the circle in x and y, and give it a radius.  So, it is BALL_SIZE/2.

That’s it.  Put the draw() in your loop() function and you are good to go.

Screen Shot 2017-05-19 at 7.25.01 AM.png

This is the result of the codes.

Wait a minute, why it is not a ping pong ball??  Well, because we ask the drawDisc() function a y-axis equal to 0 (zero).  So, when it draw, half of the ball is drawn outside of the display.  To fix that, instead you add 2 or 3 onto the ballY variable.

OK.  Now, you learned the trick.  If you add or minus a number from the ballX and ballY, it actually move the ball position.  And every time when loop() function does its looping work, it redraw (clear screen and draw) the circle at the new position.  Perhaps that is how the animation was done?  CORRECT!

u8g2.drawDisc(ballX, ballY+2, BALL_SIZE/2);

IMG_0407.jpg

Make the Ping Pong ball Move

We need to tell how the ping pong ball move.  So, let’s out of imagination, we say, next movement should be move 4 pixel away from its last position in x-axis, and move 2 pixel away from its last position in y-axis.

So, let’s define these two variables.  Actually, this will be the SPEED of the ball.  If you give a much smaller number like BALL_MOVEX=1, BALL_MOVEY=1, the ball will be slow, because it only move 1 pixel at a time.  If you give a large number, like BALL_MOVEX=10, BALL_MOVEY=10, then, the ball move very fast.

Screen Shot 2017-05-19 at 7.44.16 AM.png

you need to declare two variable to hold this speed values.

Screen Shot 2017-05-19 at 7.50.20 AM.png

So, before I draw the ball, I always update my movement in a new function call Movement().  All I do, is to update the ball position.

Screen Shot 2017-05-19 at 7.51.52 AM.png

So, in the loop(), Movement() function get calls all the time.  And at this point, the only thing I want the Movement() calculates is the new position of the ball.  Which is adding the ballMoveX & ballMoveY position.

That’s it.  That will make the ball move.

Screen Shot 2017-05-19 at 7.53.44 AM.png

OK.  The ping pong ball moves!  Yeah!!

Wait a minute, where does my ball go?  The ping pong ball goes off the screen!!!!!!

Wait a minute, the ball came back?  Why?  Because we declare the ballX and ballY to be integer, when the integer addition >= 256, it is reset back to 0 (zero).  That is why you see the ball suddenly came back from the top right corner (0,0) position when both integer got reset.

OK.  That is no nice!  Let’s make the wall bounce the ball back!

 

Make the Wall bounce the Ball

In  order to make the wall bounce, you simply have to calculate and check the position of X & Y of the ball.  In order to bounce the ball off the BOTTOM wall, you check if ballY position has gone pass (>=) the SCREEN_HEIGHT (i.e. 64 pixel).  If it does, well, REVERSE the ballMoveY polarity, by simply multiple a -1 to it.  So, the ballY starting to deduct ballMoveY because of the minus sign.  Take note, the ballX will keep going.

Now, if you want to bounce the ball off the RIGHT wall, you check if ballX position has gone pass (>=) the SCREEN_WIDTH (i.e. 128 pixel).  If it does REVERSE ballMoveX polarity with a -1. The ball started to move in the reverse X direction.

Likewise, when the ball hit or less than 0 in y-axis, you know it hit the TOP wall then, reverse your ballMoveY with -1.  If you hit the LEFT wall, then, reverse your ballMoveX with -1.

OK.  Please take note, your wall has a width of 1 pixel, that is why you later see in the code, I have to add 1 or minus 1 because the wall has a width.  I cannot use 0 (zero).  Got it?

Now, let’s see the modification we made…  What, but adding only the following 6 lines of codes.  You can capture whatever we talk about in this long winding paragraph and do what it suppose to do.

Screen Shot 2017-05-19 at 8.13.59 AM.png

That’s it!  Ping Pong ball bouncing off the wall and keeps doing that forever.

Remember, I said you can make the ball bigger by changing the BALL_SIZE value.

Also, you can change the ball speed too.  But adding more to the x-axis and y-axis movement, by modifying the BALL_MOVEX and BALL_MOVEY definition.

Final Comments

Before you see the source code below.  You know it is very hard to imagine how to write so many codes to draw the ball, make it bounce off the wall.

I even question myself when my son Jay and Kay wrote the Scratch program last year to do the Pong Game.  I was like, what?  How?  How on earth that Scratch can make it so easy to program and produce the Pong Game in 10 minutes by dragging and pasting the values here and there.

This is the first time I learned Arduino, how to connect the screen, the potentiometer.  This is also the first ever time I used C to write games.  Graphical games.  Once I have done the research and write the codes, it seems simple enough.  So, I feel very excited.  And now, I wanted to figure a way to motivate my sons to go back in time, learn how to program in C, and produce great games.

The Source Code

Create a new file, and copy paste everything here.  Compile and run.

#include <Arduino.h>
#include <U8g2lib.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 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

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.drawFrame(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
 
 // draw ball
 u8g2.drawDisc(ballX,ballY,BALL_SIZE/2);
 
}

void Movement(){

 // 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 - 1 - BALL_SIZE || ballY <=1 +BALL_SIZE/2) {
 ballMoveY *= -1; // instead of adding, reverse the polarity, start to minus
 }

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

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

void loop(void) {
 Movement();
 u8g2.firstPage();
 do {
 draw();
 } while (u8g2.nextPage());
}

 

Leave a Reply