Components and supplies
Push Button
Piezo Buzzer
Arduino Nano
Transistor NPN (BC547 or similar)
10kOhm potentiometer
Adressable WS2812B RGB LED light strip
Tools and machines
Soldering kit
Apps and platforms
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