As we continue making Pong with an Arduino, I now create the code to make the ball handle collision detection, movement and way much more. We are building Pong on a constrained piece of hardware using raw binary bits and clever algorithms. Like before I’ll live code everything with very little preparation so that you can see my thinking process. All of the heavily commented code follows below.
If you like videos like this, consider donating $1, or simply turn off Ad Blocking software. Either helps me to afford components and the books I need to make these free tutorials.
Code from the Tutorial
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
#include <LiquidCrystal.h> LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // ---------- NEW ---------- // Stores the whole gameBoard byte gameBoard[16][80] = {}; // Delay for updating the ball int ballUpdateTime = 100; // Ball starts off going horizontal byte ballXDir = 0; // Call starts off going left byte ballYDir = -1; // Starting ball x/y for storing in gameBoard byte ballX = 7; byte ballY = 35; // Temporarily stores character created for drawing // the ball before drawing to LCD byte ballCharArray[8] = {}; // Stores scores byte playerScore = 0; byte aiScore = 0; // Holds middle pixel for each paddle // Hit above go up / below go down / center go straight byte aiPaddlePos = 8; byte myPaddlePos = 8; // Ball steps // 1. Ball starts moving to the right // 2. With each move // A. Delete previous space // B. Light new space // C. Check if paddle is in new space // i. Check if ball hits PaddlePos, above PaddlePos, or below Paddle Pos // ii. Change ballXDir & ballYDir accordingly // a. PaddlePos : -XDir, YDir = 0 // b. PaddlePos - 1 : -XDir, YDir - 1 // c. PaddlePos + 1 : -XDir, YDir + 1 // iii. Clear old ball // D. Check if top wall is hit // i. XDir not changed, YDir - 1 // ii. Clear old ball // E. Check if bottom wall is hit // i. XDir not changed, YDir + 1 // ii. Clear old ball // D. Check if passes paddle // i. Change score // ii. Play sound // iii. Draw ball in center of board // iv. Clear old ball // v. YDir = 0, XDir = -XDir int GetLEDRowValue(byte ledRow, byte maxColumn){ // The starting column to create int minColumn = maxColumn - 4; // Stores the base 10 value representing the binary // value which defines what lights to turn on int ledValue = 0; // Multiplies values by 16, 8, 4, 2, 1 int multiplier = 1; // Cycle through binary values while multiplying // to create the base 10 value for(int i = maxColumn; i >= minColumn; i--){ ledValue += (gameBoard[ledRow][i] * multiplier); multiplier *= 2; } return ledValue; } // Generate the 8 values that make up the character to draw void GenerateBallArray(){ // The max column to use when forming the character using // data in the gameBoard array byte maxCol = ((ballY / 5) * 5) + 4; byte minCol = maxCol - 4; // 0 for top LCD row and 8 for bottom byte startRow = (ballX <= 7) ? 0 : 8; // Get last row value byte endRow = startRow + 8; // Get values in gameBoard and create new array with // just the balls character array if(startRow == 0){ for(int i = startRow; i < endRow; i++){ ballCharArray[i] = GetLEDRowValue(i, maxCol); } } else { for(int i = startRow; i < endRow; i++){ ballCharArray[i-8] = GetLEDRowValue(i, maxCol); } } } byte charNum = 0; void PrintBall(){ // Calculate the column we will draw in byte LCDCol = ballY / 5; // Either the top or bottom row byte LCDRow = (ballX <= 7) ? 0 : 1; // Character number to associate with the character charNum = ballY / 5; /* for(int i = 0; i < 8; i++){ Serial.print(ballCharArray[i]); Serial.print(" "); } Serial.println("\n"); */ // Assign array to the charNum lcd.createChar(charNum, ballCharArray); // Move the cursor into position lcd.setCursor(LCDCol,LCDRow); /* Serial.print("charNum "); Serial.println(charNum); Serial.print("Printing to Column "); Serial.println(LCDCol); Serial.print("Printing to Row "); Serial.println(LCDRow); */ // Draw the character lcd.write(byte(charNum)); } // Start at X: 7 Y: 35 void SetupBall(){ // Send ball in opposite direction ballYDir *= -1; // Put ball on the gameboard gameBoard[7][35] = true; } void AwardAPoint(){ if(ballY <= 8){ playerScore++; } else { aiScore++; } delay(100); // Send ball toward other player ballYDir *= -1; } void UpdateBall(){ // Short wait before update delay(ballUpdateTime); if((ballY <= 8) || (ballY >= 71)){ AwardAPoint(); } else if((ballX == 0) || (ballX == 15)){ // Hit top or bottom of screen and change Y Direction ballXDir *= -1; } else if((ballY == 69) && (ballX == myPaddlePos)){ // If hit players paddle in middle Serial.println("MIDDLE\n"); ballYDir *= -1; } else if((ballY == 69) && (ballX == (myPaddlePos + 1))){ // If hit players paddle on bottom Serial.println("BOTTOM\n"); ballYDir *= -1; ballXDir = 1; } else if((ballY == 69) && (ballX == (myPaddlePos - 1))){ // If hit players paddle on top Serial.println("TOP\n"); ballYDir *= -1; ballXDir = -1; } // Delete last ball position and add new 1 to the gameboard gameBoard[ballX][ballY] = false; // Increase ball direction based on direction set on X & Y ballX += ballXDir; ballY += ballYDir; // Set new position as true gameBoard[ballX][ballY] = true; // Create the array for the ball character GenerateBallArray(); // Clears whole LCD lcd.clear(); PrintBall(); } void setup() { Serial.begin(9600); lcd.begin(16, 2); SetupBall(); GenerateBallArray(); PrintBall(); } void loop() { UpdateBall(); } |
Leave a Reply