Components and supplies
Grove - Buzzer - Piezo
16x2 LCD display with I²C interface
NeoPixel Ring: WS2812 5050 RGB LED
Arduino Nano R3
Grove - Button (P)
Tools and machines
Soldering kit
Apps and platforms
Arduino IDE 2.0 (beta)
Project description
Code
Cyclone code
cpp
code
1//----------------------------------------------------- 2// Game "CYCLONE" for Arduino 3// Autor: Joern Weise 4// License: GNU GPl 3.0 5// Created: 20. Sep 2020 6// Update: 25. Sep 2020 7// modified by mircemk 25. Feb 2022 8//----------------------------------------------------- 9//Include libraries 10#include <Adafruit_NeoPixel.h> 11#include <Wire.h> 12#include <LiquidCrystal_I2C.h> 13#include <EEPROM.h> 14 15//Defines 16#define NUMPIXELS 12 // Popular NeoPixel ring size or edit the number of LEDs 17#define PIN 2 // Data-Pin to ring or strip 18#define PINBTN 6 // Pin for Player-button 19#define PINSCORERST 9 // Pin to reset score during first run 20 21#define DISABLEWINDOW 3 //Rounds before the LED before and after target is not valid anymore 22 23//Player-Dot speed defines 24#define STARTINTERVAL 250 //"Normal" move 25#define MAXINTERVAL 500 //Very slow move 26#define MININTERVAL 50 //Very fast move 27 28//Create objects 29LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD adress 30Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); //Init NeoPixel object 31 32bool bFirstRun, bSecureWindow; 33int iState = 1; 34int iTargetPos, iPlayerPos, iStoredHighscore, iRound, iScore, iInterval; //Vars for the game 35int iLastButtonPressed, iButtonState, iDebounceButton; //Vars to debounce button 36unsigned long iLastPlayerMove, ulLastDebounceTime; //Timer to debouce button 37unsigned long ulDebounceButton = 10; //Debounce-time 38int i = 0; 39void setup() { 40 Serial.begin(115200); 41 Serial.println("Init serial communication: DONE"); 42 43 //Begin init for WS218B-ring or -strip 44 pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) 45 pixels.clear(); // Set all pixels to "off" 46 pixels.setBrightness(20); // Set brightness to 20% 47 pixels.show(); // Send the updated pixel colors to the hardware. 48 Serial.println("Init WS218B-ring: DONE"); 49 50 //Begin init display 51 lcd.init(); 52 lcd.backlight(); 53 lcd.clear(); 54 Serial.println("Init LCD display: DONE"); 55 56 randomSeed(analogRead(0)); // Make randome more randome 57 Serial.println("Make randome more randome: DONE"); 58 59 //Read latest highscore from EEPROM 60 iStoredHighscore = EEPROM.read(0); 61 Serial.println("Last stored highscore: " + String(iStoredHighscore)); 62 63 //Init button with internal pullup-resistor 64 pinMode(PINBTN,INPUT_PULLUP); //GameBTN 65 pinMode(PINSCORERST,INPUT_PULLUP); //Reset-Pin for score 66 67 //Init some basic-vars 68 bFirstRun = true; //Enable firstrun 69 iLastButtonPressed = digitalRead(PINBTN); //Init iLastButtonPressed 70 iButtonState = digitalRead(PINBTN); //Init iButtonstate 71} 72 73void loop() { 74 int iDebounceButton = DebounceButton(); //Check and debounce button 75 76 if(!bFirstRun) 77 { 78 if(iState == 1) //Startscreen 79 { 80 bSecureWindow = true; 81 iRound = 1; 82 iScore = 0; 83 iInterval = STARTINTERVAL; 84 lcd.clear(); 85 lcd.home(); 86 lcd.print("Highscore: " + String(iStoredHighscore)); 87 lcd.setCursor(0,1); 88 lcd.print("Press button ..."); 89 iState = 2; 90 } 91 if(iState == 2) //Get Button pressed 92 { 93 if(iDebounceButton == LOW) 94 { 95 if(iRound == 1) //Only show once during game 96 Serial.println("-------- New game --------"); 97 lcd.clear(); 98 lcd.home(); 99 lcd.print("Release button"); 100 lcd.setCursor(0,1); 101 lcd.print("to start"); 102 iState = 3; 103 } 104 } 105 if(iState == 3) //Init next round 106 { 107 if(iDebounceButton == HIGH) 108 { 109 lcd.clear(); 110 lcd.home(); 111 lcd.print("Round: " + String(iRound)); 112 Serial.println("Round: " + String(iRound)); 113 lcd.setCursor(0,1); 114 lcd.print("Score: " + String(iScore)); 115 Serial.println("Score: " + String(iScore)); 116 117 iTargetPos = random(0,NUMPIXELS-1); 118 Serial.println("New target pos: " + String(iTargetPos)); 119 iPlayerPos = random(0,NUMPIXELS-1); 120 while(iTargetPos == iPlayerPos) 121 iPlayerPos = random(0,NUMPIXELS-1); 122 Serial.println("Player start pos: " + String(iPlayerPos)); 123 iState = 4; 124 } 125 } 126 if(iState == 4) //Draw target and playes dot 127 { 128 DrawNextTarget(iTargetPos, bSecureWindow); //Draw new target 129 DrawPlayer(iPlayerPos); //Draw player dot 130 iLastPlayerMove = millis(); //Update timer for moving 131 iState = 5; 132 } 133 if(iState == 5) //Wait pressing button and move player dot 134 { 135 if(iDebounceButton == LOW) 136 { 137 iState = 6; 138 } 139 else 140 { 141 unsigned long currentMillis = millis(); 142 if(currentMillis - iLastPlayerMove > iInterval) 143 { 144 iPlayerPos++; 145 if(iPlayerPos >= NUMPIXELS) 146 iPlayerPos = 0; 147 DrawNextTarget(iTargetPos, bSecureWindow); 148 DrawPlayer(iPlayerPos); 149 iLastPlayerMove = currentMillis; 150 } 151 } 152 } 153 if(iState == 6) //Check if player win 154 { 155 if(CheckPlayerPos()) //Winner or loser? 156 { 157 iScore++; //Update score 158 tone(10, 3000, 100); 159 iRound++; //Update rounds 160 iState = 2; //Go back to release button 161 if(iRound > DISABLEWINDOW) //Only target 162 { 163 bSecureWindow = false; 164 iInterval = random(MININTERVAL,MAXINTERVAL); 165 } 166 else 167 iInterval = random(STARTINTERVAL-50,MAXINTERVAL); 168 Serial.println("New interval: " + String(iInterval)); 169 } 170 else 171 iState = 90; 172 } 173 if(iState == 90) //Game ends 174 { 175 Serial.println("Game ends"); 176 lcd.clear(); 177 lcd.home(); 178 iDebounceButton = HIGH; 179 iLastButtonPressed = HIGH; 180 iButtonState = HIGH; 181 if(iScore > iStoredHighscore) //New highscore? 182 { 183 lcd.print("New highscore "); 184 lcd.setCursor(0,1); 185 lcd.print("New score: " + String(iScore)); 186 Serial.println("New highscore is " + String(iScore)); 187 EEPROM.write(0,iScore); //Store new highscore to EEPROM 188 iStoredHighscore = iScore; 189 } 190 else //Loser 191 { 192 lcd.print("Game Over"); 193 lcd.setCursor(0,1); 194 lcd.print("You lose"); 195 Serial.println("You lose!"); 196 tone(10, 150, 1000); 197 } 198 Serial.println("-------- End game --------"); 199 delay(2000); 200 iState = 1; 201 } 202 } 203 else 204 InitFirstRun(); //Init Firstrun to check LCD and WS218B-ring 205} 206 207//Function to make first run 208void InitFirstRun() 209{ 210 if(digitalRead(PINSCORERST) == LOW) //Overwrite EEPROM with "0" 211 { 212 Serial.println("Reset highscore"); 213 for(int iCnt = 0; iCnt < EEPROM.length(); iCnt++) 214 EEPROM.write(iCnt,0); 215 } 216 Serial.println("---- Start init ----"); 217 lcd.home(); 218 lcd.print("Game Cyclone"); 219 Serial.println("Game Cyclone"); 220 lcd.setCursor(0,1); 221 lcd.print("(c) M3taKn1ght"); 222 Serial.print("(c) M3taKn1ght"); 223 delay(1000); 224 lcd.clear(); 225 lcd.home(); 226 lcd.print(" mircemk"); 227 Serial.println("For az-Delivery"); 228 lcd.setCursor(0,1); 229 lcd.print("Testing ring ..."); 230 Serial.println("Testing ring ..."); 231 delay(1000); 232 pixels.clear(); 233 //Check every single LED 234 for(int i = 0; i<=51; i+=51) 235 { 236 InitRingTest(i,0,0); 237 delay(50); 238 } 239// pixels.clear(); 240// for(int i = 0; i<=255; i+=51) 241 // { 242// InitRingTest(0,i,0); 243 // delay(50); 244 //} 245// pixels.clear(); 246 // for(int i = 0; i<=255; i+=51) 247 // { 248 // InitRingTest(0,0,i); 249 // delay(50); 250 // } 251 pixels.clear(); 252 pixels.show(); 253 254 255 Serial.println("---- End init ----"); 256 bFirstRun = false; 257 Serial.println("bFirstRun: " + String(bFirstRun)); 258 Serial.println("Activate state for game"); 259} 260 261//Simple function to check LED-Ring one by one 262void InitRingTest(int iRed, int iGreen, int iBlue) 263{ 264 Serial.println("R: " + String(iRed) + " G: " + String(iGreen) + " B: " + String(iBlue)); 265 for(int iPixel = 0; iPixel < NUMPIXELS; iPixel++) 266 { 267 pixels.setPixelColor(iPixel, pixels.Color(iRed, iGreen, iBlue)); 268 pixels.show(); 269 int thisPitch = map (iPixel , 0, 12, 1000, 3000); 270 tone(10, thisPitch,120); 271 delay(50); 272 } 273} 274 275//Function to draw target an secure area for player 276void DrawNextTarget(int iPos, bool bArea) 277{ 278 pixels.clear(); 279 pixels.setPixelColor(iPos, pixels.Color(0, 255, 0)); 280 if(bArea) 281 { 282 if(iPos - 1 < 0) 283 pixels.setPixelColor(NUMPIXELS - 1, pixels.Color(255, 136, 0)); 284 else 285 pixels.setPixelColor(iPos - 1, pixels.Color(255, 136, 0)); 286 287 if(iPos + 1 >= NUMPIXELS) 288 pixels.setPixelColor(0, pixels.Color(255, 136, 0)); 289 else 290 pixels.setPixelColor(iPos + 1, pixels.Color(255, 136, 0)); 291 } 292} 293 294//Function to draw players LED 295void DrawPlayer(int iPos) 296{ 297 if(iPos == iTargetPos) //target and player-dot is equal 298 pixels.setPixelColor(iPos, pixels.Color(0, 0, 255)); //Dot color will blue 299 300 else 301 pixels.setPixelColor(iPos, pixels.Color(255, 0, 0)); //Otherwise red 302 pixels.show(); 303 tone(10, 500, 50); 304} 305 306//Function to check after pressing button, if user hit the target 307bool CheckPlayerPos() 308{ 309 if(iTargetPos == iPlayerPos) //Player hit target? 310 311 return true; 312 313 else 314 { 315 if(bSecureWindow) //LED before and after target active? 316 { 317 int iBeforeTarget = iTargetPos - 1; 318 int iAfterTarget = iTargetPos + 1; 319 if(iBeforeTarget < 0) 320 iBeforeTarget = NUMPIXELS - 1; 321 if(iAfterTarget >= NUMPIXELS) 322 iAfterTarget = 0; 323 if(iBeforeTarget == iPlayerPos || iAfterTarget == iPlayerPos) 324 return true; 325 else 326 return false; 327 328 } 329 else 330 return false; 331 } 332} 333 334//Function to debounce button 335int DebounceButton() 336{ 337 int iCurrentButtonState = digitalRead(PINBTN); 338 if(iCurrentButtonState != iLastButtonPressed) 339 ulLastDebounceTime = millis(); 340 341 if((millis() - ulLastDebounceTime) > ulDebounceButton) 342 { 343 if(iCurrentButtonState != iButtonState) 344 iButtonState = iCurrentButtonState; 345 } 346 iLastButtonPressed = iCurrentButtonState; 347 return iButtonState; 348}
Downloadable files
Schematic
circuit diagram
Schematic.jpg
Comments
Only logged in users can leave comments