Components and supplies
4
Push Button
1
Piezo Buzzer
1
Arduino Nano
1
Transistor NPN (BC547 or similar)
2
10kOhm potentiometer
1
Adressable WS2812B RGB LED light strip
Tools and machines
1
Soldering kit
Apps and platforms
1
Arduino IDE
Project description
Code
code tug
cpp
..
1#include <Adafruit_NeoPixel.h> 2 3// Pin definitions 4#define LED_PIN 6 5#define BUTTON1_PIN 2 // Player 1 button 6#define BUTTON2_PIN 3 // Player 2 button 7#define BUZZER_PIN 4 // Buzzer pin 8#define LED_INTENSITY_POT A0 // Potentiometer for LED brightness 9#define SPEED_POT A1 // Potentiometer for game speed 10#define POWER1_PIN 7 // Player 1 power move button 11#define POWER2_PIN 8 // Player 2 power move button 12 13// LED strip configuration 14#define NUM_LEDS 60 // Total number of LEDs (29 + 2 + 29) 15#define CENTER_POS 30 // Center position (0-based index) 16 17// Game constants 18#define DEBOUNCE_TIME 50 // Button debounce time in milliseconds 19#define VICTORY_FLASHES 3 // Number of victory flashes 20#define FLASH_DELAY 200 // Delay between flashes in milliseconds 21#define MIN_CLICK_SPEED 1 // Minimum pixels to move per click 22#define MAX_CLICK_SPEED 5 // Maximum pixels to move per click 23 24// Power move constants 25#define POWER_BOOST 3 // Fixed amount added to speed during power move 26#define POWER_MOVES_COUNT 3 // Number of powered moves each player gets 27#define POWER_FLASH_DURATION 500 // Duration of power move activation flash 28#define MAX_POWER_SPEED (MAX_CLICK_SPEED + 2) // Maximum speed during power move 29 30// Initialize LED strip 31Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); 32 33// Colors 34uint32_t COLOR_RED; 35uint32_t COLOR_BLUE; 36uint32_t COLOR_YELLOW; 37uint32_t COLOR_MAGENTA; 38const uint32_t COLOR_OFF = strip.Color(0, 0, 0); 39 40// Game state variables 41int flagPosition = CENTER_POS; // Current position of the center of the red flag 42unsigned long lastButton1Press = 0; 43unsigned long lastButton2Press = 0; 44bool gameActive = false; // Changed to false initially 45int clickSpeed = 1; // Number of pixels to move per click 46 47// Power move state variables 48bool player1PowerActive = false; 49bool player2PowerActive = false; 50int player1PowerMovesLeft = 0; 51int player2PowerMovesLeft = 0; 52bool player1PowerAvailable = true; // Can only use once per round 53bool player2PowerAvailable = true; // Can only use once per round 54unsigned long lastPower1Press = 0; 55unsigned long lastPower2Press = 0; 56 57bool button1LastState = HIGH; 58bool button2LastState = HIGH; 59bool power1LastState = HIGH; 60bool power2LastState = HIGH; 61 62void setup() { 63 // Initialize LED strip 64 strip.begin(); 65 strip.show(); 66 67 // Set up buttons with internal pull-up resistors 68 pinMode(BUTTON1_PIN, INPUT_PULLUP); 69 pinMode(BUTTON2_PIN, INPUT_PULLUP); 70 pinMode(POWER1_PIN, INPUT_PULLUP); 71 pinMode(POWER2_PIN, INPUT_PULLUP); 72 pinMode(BUZZER_PIN, OUTPUT); 73 pinMode(LED_INTENSITY_POT, INPUT); 74 pinMode(SPEED_POT, INPUT); 75 76 button1LastState = digitalRead(BUTTON1_PIN); 77 button2LastState = digitalRead(BUTTON2_PIN); 78 power1LastState = digitalRead(POWER1_PIN); 79 power2LastState = digitalRead(POWER2_PIN); 80 81 // Initial game state 82 resetGame(); 83} 84 85void loop() { 86 if (!gameActive) { 87 playStartSequence(); 88 } 89 90 if (gameActive) { 91 // Update LED brightness based on potentiometer 92 updateColors(); 93 94 // Update game speed based on potentiometer 95 updateGameSpeed(); 96 97 // Check for power moves 98 checkPowerMoves(); 99 100 // Check for button presses with debounce 101 checkButtons(); 102 updateLEDs(); 103 } 104} 105 106void checkPowerMoves() { 107 // Read current power button states 108 bool power1CurrentState = digitalRead(POWER1_PIN); 109 bool power2CurrentState = digitalRead(POWER2_PIN); 110 111 // Check Player 1 power move button 112 if (power1CurrentState == LOW && power1LastState == HIGH) { // Detect only falling edge 113 if (millis() - lastPower1Press > DEBOUNCE_TIME && player1PowerAvailable) { 114 activatePowerMove(1); 115 lastPower1Press = millis(); 116 } 117 } 118 119 // Check Player 2 power move button 120 if (power2CurrentState == LOW && power2LastState == HIGH) { // Detect only falling edge 121 if (millis() - lastPower2Press > DEBOUNCE_TIME && player2PowerAvailable) { 122 activatePowerMove(2); 123 lastPower2Press = millis(); 124 } 125 } 126 127 // Update power button states 128 power1LastState = power1CurrentState; 129 power2LastState = power2CurrentState; 130} 131 132void activatePowerMove(int player) { 133 if (player == 1 && player1PowerAvailable) { 134 player1PowerActive = true; 135 player1PowerMovesLeft = POWER_MOVES_COUNT; 136 player1PowerAvailable = false; 137 flashPowerMove(1); 138 } else if (player == 2 && player2PowerAvailable) { 139 player2PowerActive = true; 140 player2PowerMovesLeft = POWER_MOVES_COUNT; 141 player2PowerAvailable = false; 142 flashPowerMove(2); 143 } 144} 145 146void flashPowerMove(int player) { 147 strip.clear(); 148 // Flash player's side 149 if (player == 1) { 150 for (int i = 0; i < CENTER_POS; i++) { 151 strip.setPixelColor(i, COLOR_MAGENTA); 152 } 153 tone(BUZZER_PIN, 2000, 200); // Power move activation sound 154 } else { 155 for (int i = CENTER_POS; i < NUM_LEDS; i++) { 156 strip.setPixelColor(i, COLOR_MAGENTA); 157 } 158 tone(BUZZER_PIN, 2500, 200); // Power move activation sound 159 } 160 strip.show(); 161 delay(POWER_FLASH_DURATION); 162 updateLEDs(); 163} 164 165void playStartSequence() { 166 // First update colors for the sequence 167 updateColors(); 168 169 // Flash center position in preparation 170 for (int i = 0; i < 3; i++) { 171 // First two beeps with one frequency 172 if (i < 2) { 173 strip.clear(); 174 strip.setPixelColor(CENTER_POS, COLOR_RED); 175 strip.setPixelColor(CENTER_POS - 1, COLOR_RED); 176 strip.show(); 177 tone(BUZZER_PIN, 800, 200); // Lower frequency for ready beeps 178 delay(300); 179 180 strip.clear(); 181 strip.show(); 182 delay(300); 183 } 184 // Final beep with different frequency 185 else { 186 strip.clear(); 187 strip.setPixelColor(CENTER_POS, COLOR_MAGENTA); 188 strip.setPixelColor(CENTER_POS - 1, COLOR_MAGENTA); 189 strip.show(); 190 tone(BUZZER_PIN, 1200, 400); // Higher frequency for start beep 191 delay(400); 192 } 193 } 194 195 // Start the game 196 gameActive = true; 197 flagPosition = CENTER_POS; 198 updateLEDs(); 199} 200 201void updateColors() { 202 // Read LED intensity from potentiometer (0-255) 203 int intensity = map(analogRead(LED_INTENSITY_POT), 0, 1023, 0, 255); 204 205 // Update colors with new intensity 206 COLOR_RED = strip.Color(intensity, 0, 0); 207 COLOR_BLUE = strip.Color(0, 0, intensity); 208 COLOR_YELLOW = strip.Color(intensity, intensity, 0); 209 COLOR_MAGENTA = strip.Color(intensity, 0, intensity); 210} 211 212void updateGameSpeed() { 213 // Read speed value from potentiometer 214 clickSpeed = map(analogRead(SPEED_POT), 0, 1023, MIN_CLICK_SPEED, MAX_CLICK_SPEED); 215} 216 217void checkButtons() { 218 // Read current button states 219 bool button1CurrentState = digitalRead(BUTTON1_PIN); 220 bool button2CurrentState = digitalRead(BUTTON2_PIN); 221 222 // Check Player 1 button (pulls flag left) 223 if (button1CurrentState == LOW && button1LastState == HIGH) { // Detect only falling edge 224 if (millis() - lastButton1Press > DEBOUNCE_TIME) { 225 // Calculate move amount with a more balanced power multiplier 226 int moveAmount = clickSpeed; 227 if (player1PowerActive && player1PowerMovesLeft > 0) { 228 moveAmount = min(moveAmount + POWER_BOOST, MAX_POWER_SPEED); 229 player1PowerMovesLeft--; 230 if (player1PowerMovesLeft <= 0) { 231 player1PowerActive = false; 232 } 233 } 234 flagPosition -= moveAmount; 235 tone(BUZZER_PIN, player1PowerActive ? 800 : 1000, 20); 236 lastButton1Press = millis(); 237 } 238 } 239 240 // Check Player 2 button (pulls flag right) 241 if (button2CurrentState == LOW && button2LastState == HIGH) { // Detect only falling edge 242 if (millis() - lastButton2Press > DEBOUNCE_TIME) { 243 int moveAmount = clickSpeed; 244 if (player2PowerActive && player2PowerMovesLeft > 0) { 245 moveAmount = min(moveAmount + POWER_BOOST, MAX_POWER_SPEED); 246 player2PowerMovesLeft--; 247 if (player2PowerMovesLeft <= 0) { 248 player2PowerActive = false; 249 } 250 } 251 flagPosition += moveAmount; 252 tone(BUZZER_PIN, player2PowerActive ? 1300 : 1500, 20); 253 lastButton2Press = millis(); 254 } 255 } 256 257 // Update button states 258 button1LastState = button1CurrentState; 259 button2LastState = button2CurrentState; 260 261 // Keep flag position within bounds 262 flagPosition = constrain(flagPosition, 1, NUM_LEDS - 2); 263 264 // Check for victory conditions 265 if (flagPosition <= 1 || flagPosition >= NUM_LEDS - 2) { 266 gameActive = false; 267 celebrateVictory(); 268 } 269} 270 271void updateLEDs() { 272 strip.clear(); 273 274 // Draw the red flag (2 LEDs) 275 strip.setPixelColor(flagPosition, COLOR_RED); 276 strip.setPixelColor(flagPosition - 1, COLOR_RED); 277 278 // Draw Player 1 side (blue) 279 for (int i = 0; i < flagPosition - 1; i++) { 280 strip.setPixelColor(i, i == 0 ? COLOR_MAGENTA : COLOR_BLUE); 281 } 282 283 // Draw Player 2 side (yellow) 284 for (int i = flagPosition + 1; i < NUM_LEDS; i++) { 285 strip.setPixelColor(i, i == NUM_LEDS - 1 ? COLOR_MAGENTA : COLOR_YELLOW); 286 } 287 288 strip.show(); 289} 290 291void celebrateVictory() { 292 // Determine winner's color 293 uint32_t winnerColor = (flagPosition <= 1) ? COLOR_BLUE : COLOR_YELLOW; 294 295 // Victory tune 296 if (flagPosition <= 1) { 297 playVictoryTune(1000); // Lower pitch for Player 1 298 } else { 299 playVictoryTune(1500); // Higher pitch for Player 2 300 } 301 302 // Flash victory animation 303 for (int i = 0; i < VICTORY_FLASHES; i++) { 304 // Fill with winner's color 305 for (int j = 0; j < NUM_LEDS; j++) { 306 strip.setPixelColor(j, winnerColor); 307 } 308 strip.show(); 309 delay(FLASH_DELAY); 310 311 // Turn off 312 strip.clear(); 313 strip.show(); 314 delay(FLASH_DELAY); 315 } 316 317 delay(3000); 318 resetGame(); 319} 320 321void playVictoryTune(int baseFreq) { 322 tone(BUZZER_PIN, baseFreq, 200); 323 delay(200); 324 tone(BUZZER_PIN, baseFreq * 1.25, 200); 325 delay(200); 326 tone(BUZZER_PIN, baseFreq * 1.5, 400); 327 delay(400); 328} 329 330void resetGame() { 331 flagPosition = CENTER_POS; 332 gameActive = false; 333 player1PowerActive = false; 334 player2PowerActive = false; 335 player1PowerMovesLeft = 0; 336 player2PowerMovesLeft = 0; 337 player1PowerAvailable = true; 338 player2PowerAvailable = true; 339 updateLEDs(); 340}
Documentation
Schematic
...
Schematic JPG so Tekst.jpg

Comments
Only logged in users can leave comments