├── M5Stack-SpaceShooter.ino ├── README.md └── Screenshot.PNG /M5Stack-SpaceShooter.ino: -------------------------------------------------------------------------------- 1 | //======================== intro ======================================= 2 | // Space Shooter, basically knock-off Space Invaders 3 | // and also maybe a bit of Galaga 4 | // Written by Tyler Edwards for the Hackerbox #0020 badge 5 | // But should work on any ESP32 and Adafruit ILI9341 display 6 | // I am sorry for the messy code, you'll just 7 | // have to live with it 8 | // Tyler on GitHub: https://github.com/HailTheBDFL/ 9 | // Hackerboxes: http://hackerboxes.com/ 10 | //=========================== setup =================================== 11 | // Space Shooter with M5STACK : 2018.01.12 Transplant by macsbug 12 | // Controller : Buttons A = LEFT, B = RIGHT, C = START or SHOOTING 13 | // Github:https://macsbug.wordpress.com/2018/01/12/esp32-spaceshooter-with-m5stack/ 14 | //=================================================================== 15 | #include 16 | //============================= game variables ========================= 17 | unsigned long offsetM = 0; 18 | unsigned long offsetT = 0; 19 | unsigned long offsetF = 0; 20 | unsigned long offsetB = 0; 21 | unsigned long offsetA = 0; 22 | unsigned long offsetAF = 0; 23 | unsigned long offsetAB = 0; 24 | unsigned long offsetS = 0; 25 | int threshold = 40; 26 | boolean startPrinted = false; 27 | boolean beginGame = false; 28 | boolean beginGame2 = true; 29 | boolean play = false; 30 | int score = 0; 31 | int scoreInc = 10; 32 | int level = 1; 33 | //---------------------Player--------------------------------------- 34 | int shipX = 147; 35 | int shipY = 190; 36 | int oldShipX = 0; 37 | int oldShipY = 0; 38 | int changeShipX = 0; 39 | int changeShipY = 0; 40 | int shipSpeed = 50; 41 | boolean doSplode = false; 42 | boolean fire = false; 43 | int fFireX[5] = {0, 0, 0, 0, 0}; 44 | int fFireY[5] = {0, 0, 0, 0, 0}; 45 | int fFireAge[5] = {0, 0, 0, 0, 0}; 46 | //--------------------------Aliens---------------------------------- 47 | boolean alienLive[18]; 48 | int alienLiveCount = 18; 49 | int alienX = 7; 50 | int alienY = 25; 51 | int oldAlienX = 7; 52 | int oldAlienY = 25; 53 | int changeAlienX = 6; 54 | int changeAlienY = 0; 55 | int alienSpeed = 200; 56 | int oldAlienSpeed; 57 | int aFireX[5]; 58 | int aFireY[5]; 59 | boolean aFireAge[5]; 60 | int chanceOfFire = 2; 61 | //================================ bitmaps ======================== 62 | //your starship 63 | const int shipImgW = 14; 64 | const int shipImgH = 16; 65 | char shipImg[] = "ZZZZZZWWZZZZZZZZZZZYWWYZZZZZZZZZZWWWWZZZZZZZZZZ" 66 | "WWWWZZZZZZZZZWWWWWWZZZZZZZZWWWWWWZZZZZYZZWWWWWWZZYZZYZZWWWWWWZZ" 67 | "YZWWZZWWBBWWZZWWWWZZWBBBBWZZWWWWZWWBBBBWWZWWWWZWWWWWWWWZWWWWWWW" 68 | "WWWWWWWWWWRWWWWWWWWWWRWZZWWWWWWWWWWZZZZZWRRWWRRWZZZ"; 69 | //flames 70 | const int flamesImgW = 12; 71 | const int flamesImgH = 6; 72 | char flamesImg[] = "RZZZZZZZZZZRRZRYYRRYYRZRRZRYYRRYYRZRZZRYRZZRY" 73 | "RZZZZZRZZZZRZZZZZZRZZZZRZZZ"; 74 | //alien 75 | const int alienImgW = 14; 76 | const int alienImgH = 11; 77 | char alienImg[] = "GGGZZZZZZZZGGGZZZGZZZZZZGZZZZZGGGGGGGGGGZZZGGG" 78 | "GGGGGGGGGZGGGZGGGGGGZGGGGGGZZGGGGZZGGGGGGGGGGGGGGGGGGGGGGGGGGGG" 79 | "GGGGZZZGGZZGGZZZGZGGZGGZZGGZGGZZZZZZGZZGZZZZZ"; 80 | //ship 'sploded 81 | const int splodedImgW = 14; 82 | const int splodedImgH = 16; 83 | char splodedImg[] = "ZZZZZZWWZZZZZZZZZZRYWWYRZZZYZZZRRWWRRRRZRWYZ" 84 | "RRRRRYYRRRZWYZRYRYYRYYRRRZWWRYYYRYYYYYRZWWRYYRYRYYYYRRWWRYYYRWR" 85 | "YBRRZRRRYRRWWWRYRWZZRYYRRBBWRYRWWZZRYYBBBRRYBWWRZZRYYYRRYYZZWZR" 86 | "RWRYYRBYRZZWZZRYBRYYYYYRRZZRWWYYYWWRRRZZZZWRRWWRRRWZZZ"; 87 | //=============================== setup and loop ================== 88 | void setup() { 89 | memset(alienLive, true, 18); 90 | memset(aFireX, 0, 5); 91 | memset(aFireY, 0, 5); 92 | memset(aFireAge, 0, 5); 93 | M5.begin(); 94 | M5.Lcd.setRotation(0);//M5.Lcd.setRotation(3); 95 | M5.Lcd.fillScreen(ILI9341_BLACK); 96 | M5.Lcd.setTextColor(0x5E85); 97 | M5.Lcd.setTextSize(4); 98 | randomSeed(analogRead(6)); 99 | pinMode(BUTTON_A_PIN, INPUT_PULLUP); 100 | pinMode(BUTTON_B_PIN, INPUT_PULLUP); 101 | pinMode(BUTTON_C_PIN, INPUT_PULLUP); 102 | } 103 | //================================================================== 104 | void loop() { 105 | if(M5.BtnA.isPressed()) { left () ;} 106 | if(M5.BtnB.isPressed()) { right () ;} 107 | if(M5.BtnC.isPressed()) { select() ;} 108 | //-------------Start Screen-------------- 109 | if (millis() - offsetS >= 900 and !beginGame) { 110 | if (!startPrinted) { 111 | M5.Lcd.setCursor(77, 105); 112 | M5.Lcd.print(">START<"); 113 | startPrinted = true; 114 | offsetS = millis(); 115 | } 116 | else { 117 | M5.Lcd.fillRect(77, 105, 244, 32, ILI9341_BLACK); 118 | startPrinted = false; 119 | offsetS = millis(); 120 | } 121 | } 122 | if (beginGame and beginGame2) { 123 | M5.Lcd.fillRect(77, 105, 244, 32, ILI9341_BLACK); 124 | beginGame2 = false; 125 | play = true; 126 | } 127 | //-------------Player----------------------------------------------- 128 | if (millis() - offsetM >= shipSpeed and play) { 129 | moveShip(); 130 | offsetM = millis(); 131 | } 132 | if (oldShipX != shipX or oldShipY != shipY) { 133 | M5.Lcd.fillRect(oldShipX, oldShipY, 28, 44, ILI9341_BLACK); 134 | oldShipX = shipX; 135 | oldShipY = shipY; 136 | drawBitmap(shipImg, shipImgW, shipImgH, shipX, shipY, 2); 137 | } 138 | if (fire and play) { fireDaLazer();} 139 | if (millis() - offsetB >= 50) { 140 | for (int i = 0; i < 5; i++) { 141 | if (fFireAge[i] < 20 and fFireAge[i] > 0){keepFirinDaLazer(i);} 142 | if (fFireAge[i] == 20) { stopFirinDaLazer(i);} 143 | } 144 | offsetB = millis(); 145 | } 146 | if (millis() - offsetT > 50) { 147 | changeShipX = 0; 148 | changeShipY = 0; 149 | } 150 | //---------------Aliens-------------------------------------------- 151 | if (millis() - offsetA >= alienSpeed and play) { 152 | moveAliens(); offsetA = millis(); 153 | } 154 | if (findAlienX(5) >= 294){changeAlienX = -3;changeAlienY = 7;} 155 | if (alienX <= 6){changeAlienX = 3; changeAlienY = 7;} 156 | alienLiveCount = 0; 157 | for (int i = 0; i < 18; i++) { 158 | if (alienLive[i]) { 159 | alienLiveCount += 1; 160 | if (alienShot(i)) { 161 | M5.Lcd.fillRect(findOldAlienX(i),findOldAlienY(i),28,22,BLACK); 162 | alienLiveCount -= 1; 163 | alienLive[i] = false; 164 | score += scoreInc; 165 | } 166 | if (onPlayer(i) or exceedBoundary(i)) { 167 | gameOver(); 168 | } 169 | } 170 | } 171 | if (alienLiveCount == 1) { 172 | oldAlienSpeed = alienSpeed; 173 | if (alienSpeed > 50) { 174 | alienSpeed -= 10; 175 | } 176 | else { 177 | alienSpeed = 20; 178 | } 179 | } 180 | if (alienLiveCount == 0) { 181 | levelUp(); 182 | } 183 | M5.update(); 184 | } 185 | // functions ======================================================= 186 | void gameOver() { 187 | play = false; 188 | if (doSplode) { 189 | drawBitmap(splodedImg,splodedImgW,splodedImgH,shipX,shipY,2); 190 | } 191 | M5.Lcd.fillScreen(ILI9341_BLACK); 192 | drawScore(false); 193 | delay(1000); 194 | M5.Lcd.setCursor(17, 168); 195 | M5.Lcd.setTextSize(2); 196 | M5.Lcd.print("(Reset device to replay)"); 197 | while (1) { } 198 | } 199 | //================================================================== 200 | void drawScore(boolean win) { 201 | M5.Lcd.setCursor(53, 40); 202 | M5.Lcd.setTextColor(ILI9341_WHITE); 203 | M5.Lcd.setTextSize(4); 204 | if (win) { 205 | M5.Lcd.print("LEVEL UP!"); 206 | } 207 | else { 208 | M5.Lcd.print("GAME OVER"); 209 | } 210 | for (;millis() - offsetM <= 1000;) 211 | M5.Lcd.setCursor(59, 89); 212 | M5.Lcd.setTextSize(3); 213 | M5.Lcd.print("Score: "); M5.Lcd.print(score); 214 | offsetM = millis(); 215 | for (;millis() - offsetM <= 1000;) { 216 | } 217 | M5.Lcd.setCursor(71, 128); 218 | M5.Lcd.print("Level: "); M5.Lcd.print(level); 219 | } 220 | //================================================================== 221 | void levelUp() { 222 | play = false; 223 | memset(alienLive, true, 18); 224 | memset(aFireX, 0, 5); 225 | memset(aFireY, 0, 5); 226 | memset(aFireAge, 0, 5); 227 | alienX = 7; 228 | alienY = 25; 229 | oldAlienX = 7; 230 | oldAlienY = 25; 231 | alienSpeed = oldAlienSpeed; 232 | if (alienSpeed > 100) { 233 | alienSpeed -= 10; chanceOfFire -= 10; 234 | } 235 | else if (alienSpeed > 50) { 236 | alienSpeed -= 10; chanceOfFire -=5; 237 | } 238 | else if (alienSpeed > 25) { 239 | alienSpeed -= 5; chanceOfFire -=1; 240 | } 241 | score += 50; scoreInc += 5; 242 | changeShipX = 0; changeShipY = 0; 243 | for (unsigned long i = millis(); millis() - i <= 1600;) { 244 | if (millis() - offsetM >= 20) { 245 | M5.Lcd.fillRect(oldShipX, oldShipY, 28, 44, ILI9341_BLACK); 246 | drawBitmap(shipImg,shipImgW,shipImgH,shipX,shipY,2); 247 | drawBitmap(flamesImg,flamesImgW,flamesImgH,shipX + 1, 248 | shipY + 32,2); 249 | oldShipX = shipX; oldShipY = shipY; 250 | shipY -= 6; 251 | offsetM = millis(); 252 | } 253 | } 254 | drawScore(true); 255 | level += 1; 256 | shipX = 147; 257 | shipY = 190; 258 | for (; millis() - offsetM <= 4000;) { 259 | } 260 | M5.Lcd.fillScreen(ILI9341_BLACK); 261 | offsetM = millis(); 262 | play = true; 263 | } 264 | //================================================================== 265 | boolean alienShot(int num) { 266 | for (int i; i < 5; i++) { 267 | if (fFireAge[i] < 20 and fFireAge[i] > 0) { 268 | if (fFireX[i] > findAlienX(num) - 4 and fFireX[i] < 269 | findAlienX(num) + 28 and fFireY[i] < findAlienY(num) + 270 | 22 and fFireY[i] > findAlienY(num) + 4) { 271 | fFireAge[i] = 20; 272 | return true; 273 | } 274 | } 275 | } 276 | return false; 277 | } 278 | //================================================================== 279 | boolean onPlayer(int num) { 280 | if (findAlienX(num) - shipX < 24 and findAlienX(num) - 281 | shipX > -28 and findAlienY(num) - shipY < 32 and 282 | findAlienY(num) - shipY > -22) { 283 | doSplode = true; 284 | return true; 285 | } else { return false;} 286 | } 287 | //================================================================== 288 | boolean exceedBoundary(int num) { 289 | if (findAlienY(num) > 218) { return true; 290 | } else { return false; 291 | } 292 | } 293 | //================================================================== 294 | void moveAliens() { 295 | for (int i = 0; i < 18; i++) { 296 | if (alienLive[i]) { 297 | M5.Lcd.fillRect(findOldAlienX(i),findOldAlienY(i),28,22,BLACK); 298 | drawBitmap(alienImg,alienImgW,alienImgH,findAlienX(i), 299 | findAlienY(i),2); 300 | } 301 | } 302 | oldAlienX = alienX; oldAlienY = alienY; 303 | alienX += changeAlienX; alienY += changeAlienY; 304 | if (changeAlienY != 0) { changeAlienY = 0; } 305 | } 306 | //================================================================== 307 | int findAlienX (int num) { return alienX + 42*(num % 6); } 308 | //================================================================== 309 | int findAlienY (int num) { return alienY + 33*(num / 6); } 310 | //================================================================== 311 | int findOldAlienX(int num) { return oldAlienX + 42*(num % 6); } 312 | //================================================================== 313 | int findOldAlienY(int num) { return oldAlienY + 33*(num / 6); } 314 | //---------------------------Player--------------------------------- 315 | void fireDaLazer() { 316 | int bulletNo = -1; 317 | for (int i = 0; i < 4; i++) { 318 | if (fFireAge[i] == 0) { bulletNo = i;} 319 | } 320 | if (bulletNo != -1) { 321 | fFireAge[bulletNo] = 1; 322 | fFireX[bulletNo] = shipX + 13; 323 | fFireY[bulletNo] = shipY - 4; 324 | M5.Lcd.fillRect(fFireX[bulletNo],fFireY[bulletNo],4,3,MAGENTA); 325 | } 326 | fire = false; 327 | } 328 | //================================================================== 329 | void keepFirinDaLazer(int bulletNo) { 330 | M5.Lcd.fillRect(fFireX[bulletNo],fFireY[bulletNo],4,4,BLACK); 331 | fFireY[bulletNo] -= 8; 332 | M5.Lcd.fillRect(fFireX[bulletNo],fFireY[bulletNo],4,4,MAGENTA); 333 | fFireAge[bulletNo] += 1; 334 | } 335 | //================================================================== 336 | void stopFirinDaLazer(int bulletNo) { 337 | M5.Lcd.fillRect(fFireX[bulletNo],fFireY[bulletNo],4,4,BLACK); 338 | fFireAge[bulletNo] = 0; 339 | } 340 | //================================================================== 341 | void moveShip() { 342 | if (shipX + changeShipX < 288 and shipX + changeShipX > 343 | 6 and changeShipX != 0){ 344 | shipX += changeShipX; 345 | } 346 | if (shipY + changeShipY > 24 and shipY + changeShipY < 347 | 192 and changeShipY != 0){ 348 | shipY += changeShipY; 349 | } 350 | if (oldShipX != shipX or oldShipY != shipY) { 351 | M5.Lcd.fillRect(oldShipX, oldShipY, 28, 44, ILI9341_BLACK); 352 | oldShipX = shipX; oldShipY = shipY; 353 | drawBitmap(shipImg, shipImgW, shipImgH, shipX, shipY, 2); 354 | } 355 | } 356 | //================================================================== 357 | void drawBitmap(char img[],int imgW,int imgH,int x,int y,int scale){ 358 | uint16_t cellColor; 359 | char curPix; 360 | for (int i = 0; i < imgW*imgH; i++) { 361 | curPix = img[i]; 362 | if (curPix == 'W') { cellColor = ILI9341_WHITE; } 363 | else if (curPix == 'Y') { cellColor = ILI9341_YELLOW; } 364 | else if (curPix == 'B') { cellColor = ILI9341_BLUE; } 365 | else if (curPix == 'R') { cellColor = ILI9341_RED; } 366 | else if (curPix == 'G') { cellColor = 0x5E85; } 367 | if (curPix != 'Z' and scale == 1) { 368 | M5.Lcd.drawPixel(x + i % imgW, y + i / imgW, cellColor); 369 | } 370 | else if (curPix != 'Z' and scale > 1) { 371 | M5.Lcd.fillRect(x + scale*(i%imgW),y + 372 | scale*(i/imgW),scale,scale,cellColor); 373 | } 374 | } 375 | } 376 | //=========================== button functions ===================== 377 | void up() { 378 | if (millis() - offsetT >= 50 and play) { 379 | changeShipX = 0; changeShipY = -6; offsetT = millis(); 380 | } 381 | } 382 | //================================================================== 383 | void down() { 384 | if (millis() - offsetT >= 50 and play) { 385 | changeShipX = 0; changeShipY = 6; offsetT = millis(); 386 | } 387 | } 388 | //================================================================== 389 | void left() { 390 | if (millis() - offsetT >= 50 and play) { 391 | changeShipX = -6; changeShipY = 0; offsetT = millis(); 392 | } 393 | } 394 | //================================================================== 395 | void right() { 396 | if (millis() - offsetT >= 50 and play) { 397 | changeShipX = 6; changeShipY = 0; offsetT = millis(); 398 | } 399 | } 400 | //================================================================== 401 | void select() { 402 | if (millis() - offsetF >= 500 and play) { 403 | fire = true; offsetF = millis(); 404 | } 405 | if (!beginGame) { beginGame = true;} 406 | } 407 | //================================================================== 408 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # M5Stack-SpaceShooter 2 |
3 |
4 | 5 |

6 | 7 |

8 | 9 | 10 | ## About 11 | 12 | - Space Invaders for the M5Stack. 13 | 14 | - Written by Tyler Edwards for the Hackerbox #0020 badge - https://github.com/HailTheBDFL/ 15 | 16 | - Ported to the M5Stack by [macsbug](https://macsbug.wordpress.com/2018/01/12/esp32-spaceshooter-with-m5stack/) 17 | 18 |
19 | -------------------------------------------------------------------------------- /Screenshot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PartsandCircuits/M5Stack-SpaceShooter/1bd445ba66d1b008ef8c83a4c2225ca48aedbe33/Screenshot.PNG --------------------------------------------------------------------------------