04 - Lab IR Battle Game

# Lab 33: IR Battle Game ## **Objective** Create a two-player IR battle game where players use "guns" to shoot IR signals at "targets". The gun sends IR signals when the button is pressed, and the target receives signals to reduce lives. Each player has 5 lives represented by WS2812 LEDs, with sound effects for shooting, hits, and game over. ## **Required Components** ### **Gun (Arduino #1)** 1. **Lonely Binary UNO R3** - Main Arduino board 2. **TinkerBlock UNO R3 Shield** - Expansion shield that plugs onto the UNO R3 3. **TinkerBlock TK04** - Push Button Module (trigger) 4. **TinkerBlock TK36** - Active Buzzer Module (shooting sound) 5. **TinkerBlock TK63** - Infrared Transmitter Module (bullet) ### **Target (Arduino #2)** 1. **Lonely Binary UNO R3** - Main Arduino board 2. **TinkerBlock UNO R3 Shield** - Expansion shield that plugs onto the UNO R3 3. **TinkerBlock TK33** - WS2812 LED Strip Module (life indicator) 4. **TinkerBlock TK37** - Passive Buzzer Module (hit/death sounds) 5. **TinkerBlock TK64** - Infrared Receiver Module (bullet detection) ## **Theory** ### **IR Battle Game Mechanics** - **Gun System**: Button press triggers IR signal transmission - **Target System**: IR receiver detects incoming "bullets" - **Life System**: 5 lives represented by WS2812 LEDs - **Sound Effects**: Different sounds for shooting, hits, and death ### **Game Flow** - **Shooting**: Press button → Play shooting sound → Send IR signal - **Hit Detection**: Receive IR signal → Reduce life → Play hit sound - **Life Management**: Each hit reduces one LED - **Game Over**: All 5 lives lost → Play death sound → Game reset ### **IR Communication Protocol** - **Shoot Signal**: Specific IR pattern for bullet transmission - **Hit Confirmation**: Target acknowledges successful hit - **Game State**: Synchronized game state between players ## **Wiring Instructions** ### **Gun Arduino Wiring** #### **TK04 Push Button Pinout** - **GND** → Arduino GND - **VCC** → Arduino 5V - **NC** → No Connection - **Signal** → Arduino Digital Pin D5 #### **TK36 Active Buzzer Pinout** - **GND** → Arduino GND - **VCC** → Arduino 5V - **NC** → No Connection - **Signal** → Arduino Digital Pin D9 #### **TK63 Infrared Transmitter Pinout** - **GND** → Arduino GND - **VCC** → Arduino 5V - **NC** → No Connection - **Signal** → Arduino Digital Pin D7 #### **Gun Connection Diagram** ``` Gun UNO R3 + Shield ├── 5V ──────────────→ TK04 VCC, TK36 VCC, TK63 VCC ├── GND ─────────────→ TK04 GND, TK36 GND, TK63 GND ├── Digital Pin D5 ──→ TK04 Signal (Trigger) ├── Digital Pin D7 ──→ TK63 Signal (IR Transmitter) └── Digital Pin D9 ──→ TK36 Signal (Shooting Sound) ``` ### **Target Arduino Wiring** #### **TK33 WS2812 LED Strip Pinout** - **GND** → Arduino GND - **VCC** → Arduino 5V - **NC** → No Connection - **Signal** → Arduino Digital Pin D5 #### **TK37 Passive Buzzer Pinout** - **GND** → Arduino GND - **VCC** → Arduino 5V - **NC** → No Connection - **Signal** → Arduino Digital Pin D7 #### **TK64 Infrared Receiver Pinout** - **GND** → Arduino GND - **VCC** → Arduino 5V - **NC** → No Connection - **Signal** → Arduino Digital Pin D3 #### **Target Connection Diagram** ``` Target UNO R3 + Shield ├── 5V ──────────────→ TK33 VCC, TK37 VCC, TK64 VCC ├── GND ─────────────→ TK33 GND, TK37 GND, TK64 GND ├── Digital Pin D3 ──→ TK64 Signal (IR Receiver) ├── Digital Pin D5 ──→ TK33 Signal (WS2812 Data) └── Digital Pin D7 ──→ TK37 Signal (Hit/Death Sounds) ``` ## **Gun Code (Arduino #1)** ```cpp // Gun Code - IR Battle Game // Upload this code to the GUN Arduino #include <FastLED.h> // Pin definitions #define BUTTON_PIN 5 // TK04 Push Button on D5 #define IR_TX_PIN 7 // TK63 Infrared Transmitter on D7 #define BUZZER_PIN 9 // TK36 Active Buzzer on D9 // Game parameters #define MAX_SHOTS 10 // Maximum shots per game #define SHOT_COOLDOWN 500 // Cooldown between shots (ms) #define IR_PULSE_COUNT 5 // Number of IR pulses per shot // Variables bool buttonPressed = false; bool lastButtonState = false; unsigned long lastShotTime = 0; int shotsFired = 0; int hitsConfirmed = 0; bool gameActive = true; void setup() { // Initialize serial communication Serial.begin(9600); Serial.println("IR Battle Game - GUN"); Serial.println("===================="); // Initialize pins pinMode(BUTTON_PIN, INPUT_PULLUP); pinMode(IR_TX_PIN, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); // Start with IR transmitter off digitalWrite(IR_TX_PIN, LOW); digitalWrite(BUZZER_PIN, LOW); delay(1000); Serial.println("Gun initialized!"); Serial.println("TK04 Button: D5 (Trigger)"); Serial.println("TK63 IR Transmitter: D7 (Bullet)"); Serial.println("TK36 Buzzer: D9 (Shooting Sound)"); Serial.println(); Serial.println("Press button to shoot!"); Serial.println("Game starts in 3 seconds..."); Serial.println(); // Countdown to game start for (int i = 3; i > 0; i--) { Serial.print("Game starts in: "); Serial.println(i); delay(1000); } Serial.println("GAME START! Fire at will!"); Serial.println(); } void loop() { // Read button state bool currentButtonState = !digitalRead(BUTTON_PIN); // Handle button press (rising edge) if (currentButtonState && !lastButtonState) { buttonPressed = true; handleShoot(); } // Handle button release (falling edge) if (!currentButtonState && lastButtonState) { buttonPressed = false; } // Update button state lastButtonState = currentButtonState; // Check for game end if (shotsFired >= MAX_SHOTS && gameActive) { endGame(); } delay(10); } void handleShoot() { // Check cooldown if (millis() - lastShotTime < SHOT_COOLDOWN) { Serial.println("Cooldown! Wait before next shot."); return; } // Check if game is still active if (!gameActive) { Serial.println("Game over! Reset to play again."); return; } // Fire the shot fireShot(); // Update shot counter shotsFired++; lastShotTime = millis(); // Display shot info Serial.print("Shot #"); Serial.print(shotsFired); Serial.print(" fired! Shots remaining: "); Serial.println(MAX_SHOTS - shotsFired); } void fireShot() { // Play shooting sound playShootingSound(); // Send IR bullet signal sendIRBullet(); Serial.println("BANG! Bullet fired!"); } void playShootingSound() { // Shooting sound effect tone(BUZZER_PIN, 800, 100); // High pitch "bang" delay(100); tone(BUZZER_PIN, 600, 50); // Lower pitch "recoil" delay(50); noTone(BUZZER_PIN); } void sendIRBullet() { // Send IR bullet pattern // This creates a distinctive IR signal for bullet detection for (int i = 0; i < IR_PULSE_COUNT; i++) { // Send IR pulse digitalWrite(IR_TX_PIN, HIGH); delayMicroseconds(1000); // 1ms pulse digitalWrite(IR_TX_PIN, LOW); delayMicroseconds(1000); // 1ms gap } // Send end marker digitalWrite(IR_TX_PIN, HIGH); delayMicroseconds(5000); // 5ms end marker digitalWrite(IR_TX_PIN, LOW); } void endGame() { gameActive = false; Serial.println("=== GAME OVER ==="); Serial.print("Total shots fired: "); Serial.println(shotsFired); Serial.print("Hits confirmed: "); Serial.println(hitsConfirmed); Serial.print("Accuracy: "); if (shotsFired > 0) { Serial.print((hitsConfirmed * 100) / shotsFired); Serial.println("%"); } else { Serial.println("0%"); } Serial.println(); Serial.println("Press button to reset game..."); // Play game over sound playGameOverSound(); } void playGameOverSound() { // Game over sound effect tone(BUZZER_PIN, 400, 200); delay(200); tone(BUZZER_PIN, 300, 200); delay(200); tone(BUZZER_PIN, 200, 400); delay(400); noTone(BUZZER_PIN); } void resetGame() { shotsFired = 0; hitsConfirmed = 0; gameActive = true; lastShotTime = 0; Serial.println("Game reset! Ready to shoot!"); Serial.println(); } // Function to receive hit confirmation (if using two-way communication) void receiveHitConfirmation() { // This would be used if implementing two-way IR communication hitsConfirmed++; Serial.print("Hit confirmed! Total hits: "); Serial.println(hitsConfirmed); } ``` ## **Target Code (Arduino #2)** ```cpp // Target Code - IR Battle Game // Upload this code to the TARGET Arduino #include <FastLED.h> // Pin definitions #define LED_PIN 5 // TK33 WS2812 LED Strip on D5 #define BUZZER_PIN 7 // TK37 Passive Buzzer on D7 #define IR_RX_PIN 3 // TK64 Infrared Receiver on D3 #define NUM_LEDS 5 // TK33 has 5 WS2812 LEDs // LED array CRGB leds[NUM_LEDS]; // Game parameters #define MAX_LIVES 5 // Maximum lives per game #define HIT_DETECTION_TIME 100 // Time to detect IR signal (ms) #define DEBOUNCE_TIME 200 // Debounce time between hits (ms) // Variables int currentLives = MAX_LIVES; bool irSignalDetected = false; bool lastIRSignal = false; unsigned long lastHitTime = 0; int hitsReceived = 0; bool gameActive = true; bool targetDestroyed = false; void setup() { // Initialize serial communication Serial.begin(9600); Serial.println("IR Battle Game - TARGET"); Serial.println("======================="); // Initialize WS2812 LED strip FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); FastLED.setBrightness(100); // Initialize pins pinMode(IR_RX_PIN, INPUT); pinMode(BUZZER_PIN, OUTPUT); // Initialize LEDs to show full lives initializeLives(); delay(1000); Serial.println("Target initialized!"); Serial.println("TK33 WS2812 LED Strip: D5 (Life Indicator)"); Serial.println("TK37 Passive Buzzer: D7 (Hit/Death Sounds)"); Serial.println("TK64 IR Receiver: D3 (Bullet Detection)"); Serial.println(); Serial.println("Waiting for incoming fire..."); Serial.println("Game starts in 3 seconds..."); Serial.println(); // Countdown to game start for (int i = 3; i > 0; i--) { Serial.print("Game starts in: "); Serial.println(i); delay(1000); } Serial.println("TARGET ACTIVE! Incoming fire expected!"); Serial.println(); } void loop() { // Read IR receiver bool currentIRSignal = digitalRead(IR_RX_PIN); // Handle IR signal detection (active high) if (currentIRSignal && !lastIRSignal) { // IR signal started irSignalDetected = true; handleIncomingFire(); } else if (!currentIRSignal && lastIRSignal) { // IR signal ended irSignalDetected = false; } // Update IR signal state lastIRSignal = currentIRSignal; // Check for game over if (currentLives <= 0 && gameActive) { targetDestroyed = true; gameOver(); } delay(10); } void handleIncomingFire() { // Check debounce time if (millis() - lastHitTime < DEBOUNCE_TIME) { return; } // Check if game is still active if (!gameActive) { return; } // Process the hit processHit(); // Update hit counter hitsReceived++; lastHitTime = millis(); Serial.print("HIT! Lives remaining: "); Serial.println(currentLives); } void processHit() { // Reduce life currentLives--; // Update LED display updateLifeDisplay(); // Play hit sound playHitSound(); // Check if target is destroyed if (currentLives <= 0) { playDeathSound(); } } void initializeLives() { // Set all LEDs to green (full lives) for (int i = 0; i < NUM_LEDS; i++) { leds[i] = CRGB::Green; } FastLED.show(); Serial.print("Lives initialized: "); Serial.print(currentLives); Serial.println(" / 5"); } void updateLifeDisplay() { // Clear all LEDs FastLED.clear(); // Set remaining lives to green for (int i = 0; i < currentLives; i++) { leds[i] = CRGB::Green; } // Set lost lives to red for (int i = currentLives; i < NUM_LEDS; i++) { leds[i] = CRGB::Red; } FastLED.show(); Serial.print("Life display updated: "); Serial.print(currentLives); Serial.println(" lives remaining"); } void playHitSound() { // Hit sound effect tone(BUZZER_PIN, 600, 100); // Medium pitch "hit" delay(100); tone(BUZZER_PIN, 400, 100); // Lower pitch "damage" delay(100); noTone(BUZZER_PIN); } void playDeathSound() { // Death sound effect Serial.println("*** TARGET DESTROYED! ***"); // Dramatic death sound tone(BUZZER_PIN, 800, 200); delay(200); tone(BUZZER_PIN, 600, 200); delay(200); tone(BUZZER_PIN, 400, 200); delay(200); tone(BUZZER_PIN, 200, 400); delay(400); noTone(BUZZER_PIN); // Flash all LEDs red for (int i = 0; i < 5; i++) { for (int j = 0; j < NUM_LEDS; j++) { leds[j] = CRGB::Red; } FastLED.show(); delay(200); FastLED.clear(); FastLED.show(); delay(200); } } void gameOver() { gameActive = false; Serial.println("=== TARGET DESTROYED ==="); Serial.print("Total hits received: "); Serial.println(hitsReceived); Serial.print("Survival time: "); Serial.print((millis() / 1000)); Serial.println(" seconds"); Serial.println(); Serial.println("Target destroyed! Game over!"); Serial.println("Reset Arduino to play again..."); // Keep death animation running while (true) { // Continuous red flash for (int i = 0; i < NUM_LEDS; i++) { leds[i] = CRGB::Red; } FastLED.show(); delay(500); FastLED.clear(); FastLED.show(); delay(500); } } // Function to send hit confirmation (if using two-way communication) void sendHitConfirmation() { // This would be used if implementing two-way IR communication // to confirm hits back to the gun Serial.println("Hit confirmation sent to gun"); } ``` ## **Advanced Two-Way Battle Game** ```cpp // Advanced Two-Way Battle Game // Both Arduinos can be gun and target simultaneously #include <FastLED.h> // Pin definitions #define BUTTON_PIN 5 // TK04 Push Button (Gun mode) #define LED_PIN 5 // TK33 WS2812 LED Strip (Target mode) #define IR_TX_PIN 7 // TK63 Infrared Transmitter (Gun mode) #define IR_RX_PIN 3 // TK64 Infrared Receiver (Target mode) #define BUZZER_PIN 9 // TK36 Active Buzzer (Gun mode) #define PASSIVE_BUZZER_PIN 7 // TK37 Passive Buzzer (Target mode) #define NUM_LEDS 5 // TK33 has 5 WS2812 LEDs // LED array CRGB leds[NUM_LEDS]; // Game parameters #define MAX_LIVES 5 #define MAX_SHOTS 10 #define SHOT_COOLDOWN 500 #define HIT_DEBOUNCE 200 // Game states enum GameState { STATE_WAITING, STATE_SHOOTING, STATE_HIT, STATE_GAME_OVER }; // Variables GameState currentState = STATE_WAITING; int lives = MAX_LIVES; int shotsFired = 0; int hitsScored = 0; bool buttonPressed = false; bool lastButtonState = false; bool irSignalDetected = false; bool lastIRSignal = false; unsigned long lastShotTime = 0; unsigned long lastHitTime = 0; bool gameActive = true; void setup() { Serial.begin(9600); Serial.println("Advanced IR Battle Game"); Serial.println("======================="); // Initialize pins pinMode(BUTTON_PIN, INPUT_PULLUP); pinMode(IR_TX_PIN, OUTPUT); pinMode(IR_RX_PIN, INPUT); pinMode(BUZZER_PIN, OUTPUT); // Initialize WS2812 LED strip FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); FastLED.setBrightness(100); // Initialize LEDs initializeLives(); delay(1000); Serial.println("Advanced battle system initialized!"); Serial.println("Press button to shoot, receive hits to lose lives"); Serial.println("Game starts in 3 seconds..."); Serial.println(); // Countdown for (int i = 3; i > 0; i--) { Serial.print("Game starts in: "); Serial.println(i); delay(1000); } Serial.println("BATTLE START!"); Serial.println(); } void loop() { // Read inputs bool currentButtonState = !digitalRead(BUTTON_PIN); bool currentIRSignal = digitalRead(IR_RX_PIN); // Handle button press (shooting) if (currentButtonState && !lastButtonState) { handleShoot(); } // Handle IR signal detection (being hit) if (currentIRSignal && !lastIRSignal) { handleHit(); } // Update states lastButtonState = currentButtonState; lastIRSignal = currentIRSignal; // Check game over conditions if (lives <= 0 || shotsFired >= MAX_SHOTS) { if (gameActive) { gameOver(); } } delay(10); } void handleShoot() { if (!gameActive || millis() - lastShotTime < SHOT_COOLDOWN) { return; } // Fire shot fireShot(); shotsFired++; lastShotTime = millis(); Serial.print("Shot fired! Shots: "); Serial.print(shotsFired); Serial.print("/"); Serial.print(MAX_SHOTS); Serial.print(" | Lives: "); Serial.print(lives); Serial.println("/5"); } void handleHit() { if (!gameActive || millis() - lastHitTime < HIT_DEBOUNCE) { return; } // Process hit lives--; hitsScored++; lastHitTime = millis(); updateLifeDisplay(); playHitSound(); Serial.print("HIT! Lives: "); Serial.print(lives); Serial.println("/5"); if (lives <= 0) { playDeathSound(); } } void fireShot() { // Shooting sound tone(BUZZER_PIN, 800, 100); delay(100); tone(BUZZER_PIN, 600, 50); delay(50); noTone(BUZZER_PIN); // Send IR bullet for (int i = 0; i < 5; i++) { digitalWrite(IR_TX_PIN, HIGH); delayMicroseconds(1000); digitalWrite(IR_TX_PIN, LOW); delayMicroseconds(1000); } digitalWrite(IR_TX_PIN, HIGH); delayMicroseconds(5000); digitalWrite(IR_TX_PIN, LOW); } void initializeLives() { for (int i = 0; i < NUM_LEDS; i++) { leds[i] = CRGB::Green; } FastLED.show(); } void updateLifeDisplay() { FastLED.clear(); for (int i = 0; i < lives; i++) { leds[i] = CRGB::Green; } for (int i = lives; i < NUM_LEDS; i++) { leds[i] = CRGB::Red; } FastLED.show(); } void playHitSound() { tone(BUZZER_PIN, 600, 100); delay(100); tone(BUZZER_PIN, 400, 100); delay(100); noTone(BUZZER_PIN); } void playDeathSound() { tone(BUZZER_PIN, 800, 200); delay(200); tone(BUZZER_PIN, 600, 200); delay(200); tone(BUZZER_PIN, 400, 200); delay(200); tone(BUZZER_PIN, 200, 400); delay(400); noTone(BUZZER_PIN); } void gameOver() { gameActive = false; Serial.println("=== GAME OVER ==="); Serial.print("Shots fired: "); Serial.println(shotsFired); Serial.print("Hits scored: "); Serial.println(hitsScored); Serial.print("Lives remaining: "); Serial.println(lives); if (lives <= 0) { Serial.println("YOU WERE DESTROYED!"); } else { Serial.println("OUT OF AMMO!"); } // Death animation for (int i = 0; i < 10; i++) { for (int j = 0; j < NUM_LEDS; j++) { leds[j] = CRGB::Red; } FastLED.show(); delay(200); FastLED.clear(); FastLED.show(); delay(200); } } ``` ## **Code Explanation** ### **Gun System Features** - **Button Trigger**: Press button to fire shots - **Shooting Sound**: Active buzzer plays shooting sound effects - **IR Transmission**: Sends IR signals as "bullets" - **Shot Cooldown**: Prevents rapid-fire shooting - **Shot Counter**: Tracks total shots fired ### **Target System Features** - **IR Detection**: Receives IR signals as incoming bullets - **Life Management**: 5 lives represented by WS2812 LEDs - **Hit Sounds**: Passive buzzer plays hit and death sounds - **Visual Feedback**: LED strip shows remaining lives - **Game Over**: Death animation when all lives lost ### **Game Mechanics** - **Life System**: Each hit reduces one life (LED) - **Sound Effects**: Different sounds for shooting, hits, and death - **Visual Feedback**: LED colors indicate life status - **Game States**: Waiting, shooting, hit, game over states ### **IR Communication** - **Bullet Signal**: Specific IR pattern for bullet transmission - **Hit Detection**: IR receiver detects incoming signals - **Debouncing**: Prevents multiple hits from single shot - **Range**: IR communication works within line of sight ## **Troubleshooting** ### **IR Communication Issues:** - Check TK63/TK64 wiring and alignment - Verify line of sight between modules - Test with different distances - Check for ambient IR interference ### **Button Issues:** - Check TK04 wiring (D5 pin) - Verify pull-up resistor configuration - Test with simple digitalRead - Check for loose connections ### **LED Strip Issues:** - Check TK33 wiring (D5 pin) - Verify power supply (5V, sufficient current) - Test with simple color setting - Check FastLED library installation ### **Buzzer Issues:** - Check TK36/TK37 wiring - Verify power connections - Test with simple tone() function - Check for pin conflicts ## **Applications** ### **Gaming** - **Laser Tag**: IR-based combat games - **Target Practice**: Shooting range simulation - **Battle Games**: Multi-player combat systems - **Training**: Military/police training systems ### **Educational** - **IR Communication**: Learn about wireless communication - **Game Design**: Practice game mechanics programming - **Sensor Integration**: Learn about sensor networks - **Real-time Systems**: Practice responsive system design ### **Entertainment** - **Party Games**: Interactive entertainment systems - **Theme Parks**: Interactive attractions - **Arcade Games**: Custom arcade systems - **Team Building**: Group activity systems ### **Prototyping** - **Proof of Concept**: Test IR communication ideas - **Sensor Networks**: Build multi-node systems - **Game Mechanics**: Develop interactive systems - **Wireless Systems**: Practice wireless communication ## **Next Steps** - Add multiple players - Implement different weapon types - Create power-ups and special effects - Add wireless score tracking ## **Resources** - **IR Communication**: Infrared communication principles - **Game Design**: Interactive game mechanics - **FastLED Library**: WS2812 LED control - **Real-time Systems**: Responsive system design