PROJECT: PONG
Step 1 - Build the Project

The code behind Pong is straightforward: "Did the ball collide with the paddle at a given time?". In this program, the code is checking: "Did the player press the button at the right time to 'strike' the ball?".

Step 2 - Upload the Code

/* * Single line pong using the LEDStrip, when the pixel is at the * end of the strip, press your button to send it back to your * opponent. */ //Include the LEDStrip library to use the commands #include "LEDStrip.h" const byte numPixels = 15; //number of pixels on a strip const byte middlePixel = numPixels/2; //Where the ball will reset //Color values on the strip range from 0 to 300 int color; //The color of the strip and ball depends on the player const int p1Color = 75;//Color for p1's points const int p2Color = 225;//Color for p2's points long timer = millis(); //Timer to control movement of pixel //Flags for early presses, so you can't hold the button down bool p1Early = false; bool p2Early = false; //Flags for when players press the button at the correct time bool p1Hit = false; bool p2Hit = false; int pixel = 7; //Starting position of the pixel int ballDelay = 150;//The number of milliseconds between pixel moves int Direction = 1; //Direction of travel of the pixel. 1 or -1 /* * Make the LED strip object LEDStrip strip * = LEDStrip(numPixels, dataPin (DI), clockPin(CI)); */ LEDStrip strip = LEDStrip(numPixels, 13, 12); void setup() { //Buttons pinMode(A5,INPUT_PULLUP); //p1Button pinMode(2,INPUT_PULLUP);//p2Button } void loop() { //Check the players' buttons int p1Button = digitalRead(A5); int p2Button = digitalRead(2); //If P1 button pressed while at pixel 0, P1 gets a hit if ((p1Button == LOW)&&(pixel == 0)){ p1Hit = true; } //If P2 button pressed while at pixel 14, P2 gets a hit if ((p2Button == LOW)&&(pixel == numPixels-1)){ p2Hit = true; } //If the 'ballSpeed' time has passed, this if loop is true. if (millis() - timer > ballDelay){ timer = millis(); //Reset the timer //If P1 hits and didn't swing early when pixel is 0 if ((pixel == 0)&&((p1Hit == true)&&(p1Early == false))){ Direction = Direction*-1; //Change direction color = p2Color; //Make the pixel P2's color p1Hit = false; //Reset the 'hit' flag for P1 } //If P1 didn't hit, or swings early when pixel is 0 else if ((pixel == 0)&&((p1Hit == false)||(p1Early == true))){ pixel = middlePixel; //Reset pixel to middle of strip color = p2Color; //Make pixel P2's color Direction = Direction*-1; //Change direction //Flash P2's color to indicate a point for p2 strip.setPixel(strip.ALL,p2Color); strip.draw(); delay(1000); strip.clear(); p1Hit = false; //Reset P1's hit flag } //If P2 has hit, is not early, and pixel is in correct position... if ((p2Hit == true)&&(pixel == numPixels-1)&&(p2Early == false)){ Direction = Direction*-1; //Change direction color = p1Color; //Set pixel to P1's color (225 is cyan) p2Hit = false; //Clear P2's hit flag } //if pixel is in correct position and P2 misses or swings early else if (((p2Hit == false)||(p2Early == true))&&(pixel == numPixels-1)){ pixel = middlePixel; //Set pixel to middle of strip color = p1Color; //Set pixel to P1's color Direction = Direction*-1; //Change direction //Flash P1's color to indicate point earned strip.setPixel(strip.ALL,p1Color); strip.draw(); delay(1000); strip.clear(); p2Hit = false;//Clear P2's hit flag } strip.setPixel(pixel,-1); //clear the old pixel pixel = pixel + Direction; //Move the pixel //If just transitioning to pixel 0 and P1 pressing button if ((pixel == 0)&&(p1Button == LOW)){ p1Early = true; //Flag that P1 swings early } //If just transitioning to last pixel and P2 pressing button else if ((pixel == numPixels-1)&&(p2Button == LOW)){ p2Early = true; //Flag that P2 swings early } //If early swing flags not set when moving pixel, clear them else{ p1Early = false; p2Early = false; } strip.setPixel(pixel,color); //Write the new pixel } strip.draw(); //Draw what we wrote to the strip } //Update the ballDelay variable for faster speeds. Try to lower ballDelay //each time there is a confirmed hit by a player! // (c) 2017 Let's Start Coding. License: www.letsstartcoding.com/bsdlicense
 

Step 3 - Read the Walkthrough

First include the LEDStrip library. This library gives you access to a new set of commands (called methods) that make using the LED Strip easier. Without including the library, the Arduino software won’t recognize the new methods.

Next, create an integer variable called numPixels. Its value should be equal to the number of LEDs on your strip. 

The middlePixel variable is an integer based on your numPixels variable. Integers truncate (cut off) all decimal places, so if you have 15 pixels, 15/2 will be an integer value of 7. 

The integer variable named color holds a value from -1 to 300. 

Each player has a color that flashes when they score a point. Set those color values with p1Color and p2Color.

The variable timer is a ‘long’ variable type. It takes up more program space than an int, but a long can hold very large numbers. Because long is counting milliseconds, it will quickly grow very large. The value of long is set equal to the value of millis(). Millis() is a function that automatically starts counting up when your program starts running.

The next four variables are boolean variables. They can only have one of two states: true or false. You’re using them here to mark that an event has happened. Since there are only two possibilities (the event happened or it did not), bool is best.

Your pixel variable holds the number of the active pixel that the code is modifying.

The ballDelay variable holds the amount of time (in milliseconds) that the program waits before moving the pixel and checking whether a player has hit the ball.

The Direction variable tells whether the pixel is moving toward the tip of the strip or toward the base. A -1 means the pixel is moving toward the base of the strip.

To tell the library the name & attributes of your LED Strip, you create an object. In this case, the object is called ‘strip’ and it has ‘numPixel’ pixels, the data pin is number 11, and the clock pin is number 12 on your carrier board.

In the setup() section, you set both players’ buttons as INPUT_PULLUP pin mode. The button will now send a LOW signal to Maker Board when the button is pressed. 

In the loop, there are only 3 lines of code that are guaranteed to run every loop: the digitalRead of the buttons and the strip.draw() command. Everything else depends on the players, so there are many if statements. Because there are two players, many of the statements are duplicated.

The first two if statements check “was the button pressed and was the pixel in the correct position?”. The && is an AND statement, so both statements have to be true before the code inside the if statement runs. If both of those things are true, then the player’s hit variable becomes true. 

Next is a series of nested if statements. These statements are only checked if the statement they are nested inside is true. Here you’ll see the value of indentation and the way curly braces are placed. 

If millis (the automatic counter) minus the timer variable, then timer and millis() are set equal. This has the effect of creating a 250 millisecond timer without using a delay.

For the next if statement, three conditions have to be true before the if statement executes. First, player1 must have pressed their button. Second, the pixel must be at the base of the strip. Third, player1 must not have triggered the p1Early variable by holding the button. Only when all of those things are true, the pixel will change color, change direction, and reset the p1Hit variable to false.

The else if statement checks the alternative outcomes when pixel == 0. If player1 didn’t swing soon enough or  (||) player 1 swung too early, the pixel is set to the middle, and the pixel direction is changed. 

Then, the else if statement flashes the entire strip the color of the p2 team for 1 second to indicate p2 has scored a point. The p1Hit variable is reset for the next round. 

The next if-else if statements are repeating the same checks as above for player 2. 

All of the checks for the swings are only useful if the pixel is at either end of the strip. Otherwise, the code just keeps the pixel moving. The speed at which the pixel moves is determined by the ballDelay variable. The lower that variable, the faster the ball moves. Here, strip.setPixel() clears the previous pixel and then updates the pixel’s position by “Direction”. That could mean the pixel is moving up or down the strip, depending on whether Direction is positive or negative.

The order of the next statements in the code is very important. The pixel has just been moved one spot. Now you will immediately ask the question “Did the pixel just move to the end of the strip while the button was pressed?”. If that is true, then player1 was holding the button down when the pixel moved on to the end of the strip and they swung too early! The ‘p1Early’ variable is set to true so that next time through the loop, p1Early will mean they miss the ball.

The same check occurs for p2. If neither player has swung early at this point, the Early variables are set to false.

Now that pixel has a new position, it will be updated to the color of the player who has to hit the ball next.

Finally you’ve completed the if loop. The strip.draw() command will display the new pixel and color. 

Whoa! That’s a lot of code. Remember all of this code runs with each loop. If your ballDelay variable is 250, the loop runs 4 times per second.