Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Tired of playing the usual buzz wire game? How about spicing things up a bit using an Arduino?
This project adds a multi level game with a few simple melodies to an existing or self-built buzz wire game. There are 9 levels, in the first level you get 9 lives and then 1 life less in each consecutive level. You loose 1 life each time you touch the wire:
In addition to the wire and the loop that you have to move along the wire, two extra points are required: a start and an end point that you can touch with the loop to signal the start and completion of a level. I used a of copper wire at the start and end of the buzz wire:
The loop pen is connected to the GND, the Arduino detects touches when one of the contact points (start, wire or end) is connected to the GND through the loop.
The code is written to use a 20x4 LCD character display with an I2C adapter:
https://www.instructables.com/How-to-Use-I2C-Serial-LCD-20X4-Yellow-Backlight/
It should work on a 16x2 as well, just have to shorten the texts a bit.
It should also work without an I2C adapter however, just wire the display up in the usual manner:
https://www.arduino.cc/en/Tutorial/LibraryExamples/HelloWorld
The code needs to be adjusted, follow the comments in the code.
The code contains a self test that you can uncomment to test if the wiring works correctly:
// uncomment the next line to show a self test screen
// selfTestLoop();
Just leave a comment if you like this project or if you have questions / difficulties building it.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//use this include instead when not using an I2C display
//#include <LiquidCrystal.h>
#include "pitches.h"
// use a 20 chars and 4 line display
// some of the lcd cursor/print statements will have to be adjusted to fit on a 16x2 screen
const int lcdColumns = 20;
const int lcdRows = 4;
// set the LCD address to 0x27
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
// use the following lines instead when not using an I2C display:
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
//const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
//LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// the hook the player uses to play the game is connected to the GND pin
// the pin that the start point is attached to
const int startPin = 8;
// the pin that the end point is attached to
const int endPin = 9;
// the pin that the wire is attached to
const int wirePin = 10;
// the pin that the speaker is attached to
const int speakerPin = 7;
// total number of levels
const int noLevels = 9;
// number of lives in level 1 (each next level has 1 life less)
const int livesLevel1 = 9;
// custom character for a heart
byte heart[8] = {
B00000,
B01010,
B11111,
B11111,
B01110,
B00100,
B00000,
B00000,
};
// custom character for a lost heart
byte heartEmpty[8] = {
B00000,
B01010,
B10101,
B10001,
B01010,
B00100,
B00000,
B00000,
};
// custom character for a medal
byte medal[8] = {
B11111,
B10001,
B10001,
B01010,
B01110,
B11111,
B11111,
B01110,
};
// setup function
void setup()
{
// set the start, end and wire pins to input with an internal pull-up mode
pinMode(startPin, INPUT_PULLUP);
pinMode(endPin, INPUT_PULLUP);
pinMode(wirePin, INPUT_PULLUP);
// set the speaker pin to output mode
pinMode(speakerPin, OUTPUT);
// initialize the LCD display
// skip the next line when not using an I2C display
lcd.init();
// enable the LCD backlight
// skip the next line when not using an I2C display
lcd.backlight();
// set the number of columns and rows in the LCD display
lcd.begin(lcdColumns, lcdRows);
// create the custom characters
lcd.createChar(1, heart);
lcd.createChar(2, heartEmpty);
lcd.createChar(3, medal);
// uncomment the next line to show a self test screen
// selfTestLoop();
}
// main game loop
void loop()
{
// variable to keep track if we lost the game or not
bool gameOver = false;
// print the welcome message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Buzz Wire Deluxe");
delay(2000);
// total number of lives within a level
int totalLives;
// lives left within a level
int currentLives;
// loop over the levels
for (int level = 1 ; level <= noLevels ; level++) {
// each next level starts with 1 less lives
totalLives = livesLevel1 - level + 1;
currentLives = totalLives;
// print the level start message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Level ");
lcd.print(level);
lcd.setCursor(0, 1);
lcd.print("Touch start to begin");
// wait until start is touched
while (!isStartTouched()) {
}
// print get ready
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Get ready... ");
// play the level start melody
melodyLevelStart();
// print go! and wait a second
lcd.print("GO!");
delay(1000);
// clear the screen, print the level number and initial lives
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Level ");
lcd.print(level);
printLives(currentLives, totalLives);
// level loop, repeat until level completed or no lives left
do {
bool wireTouched = false;
bool endTouched = false;
// wait for the wire or end to be touched
do {
wireTouched = isWireTouched();
endTouched = isEndTouched();
} while (!wireTouched && !endTouched);
if (wireTouched) {
// wire was touched, reduce lives and continue
currentLives--;
} else {
// end touched, break the level loop
break;
}
// update the lives on the display
printLives(currentLives, totalLives);
// play the wire touched melody
melodyLevelWireTouched();
} while (currentLives > 0);
if (currentLives > 0) {
// level was completed with at least 1 life
// print a level finished message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Level finished!!!");
// play the level finished melody
melodyLevelFinished();
// wait 3 seconds
delay(3000);
} else {
// level was ended because lives dropped to 0, game over! break the levels loop
break;
}
}
// levels loop was ended, check why
if (currentLives == 0) {
// levels loop was ended because of a game over
// print game over message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Game over!!!");
// play the game over melody
melodyLevelGameOver();
} else {
// all levels completed
// print a champion message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("\x03\x03 Champion \x03\x03");
// play the champion melody
melodyChampion();
}
// wait 3 seconds
delay(3000);
// show a touch start to begin message
lcd.setCursor(0, 1);
lcd.print("Touch start to begin");
// wait for start to be touched
while (!isStartTouched()) {
}
}
// print the number of lives
void printLives(int currentLives, int totalLives) {
lcd.setCursor(0, 1);
lcd.print("Lives ");
for (int i = 1 ; i <= totalLives ; i++) {
if (i <= currentLives) {
lcd.print("\1");
} else {
lcd.print("\2");
}
}
}
// test if the wire is being touched
bool isWireTouched() {
return !digitalRead(wirePin);
}
// test if the start is being touched
bool isStartTouched() {
return !digitalRead(startPin);
}
// test if the end is being touched
bool isEndTouched() {
return !digitalRead(endPin);
}
// play the level start melody
void melodyLevelStart() {
tone(speakerPin, NOTE_C4, 200);
delay(600);
tone(speakerPin, NOTE_C4, 200);
delay(600);
tone(speakerPin, NOTE_C4, 200);
delay(600);
tone(speakerPin, NOTE_C5);
delay(600);
noTone(speakerPin);
}
// play the level finished melody
void melodyLevelFinished() {
tone(speakerPin, NOTE_C4);
delay(300);
tone(speakerPin, NOTE_D4);
delay(300);
tone(speakerPin, NOTE_E4);
delay(300);
tone(speakerPin, NOTE_F4);
delay(300);
tone(speakerPin, NOTE_G4);
delay(300);
noTone(speakerPin);
}
// play the wire touched melody
void melodyLevelWireTouched() {
tone(speakerPin, NOTE_A4);
delay(300);
tone(speakerPin, NOTE_GS4);
delay(300);
tone(speakerPin, NOTE_G4);
delay(1000);
noTone(speakerPin);
}
// play the game over melody
void melodyLevelGameOver() {
tone(speakerPin, NOTE_A4);
delay(300);
tone(speakerPin, NOTE_GS4);
delay(300);
tone(speakerPin, NOTE_G4);
delay(300);
tone(speakerPin, NOTE_FS4);
delay(300);
tone(speakerPin, NOTE_F4);
delay(300);
tone(speakerPin, NOTE_E4);
delay(300);
tone(speakerPin, NOTE_DS4);
delay(300);
tone(speakerPin, NOTE_D4);
delay(300);
tone(speakerPin, NOTE_CS4);
delay(300);
tone(speakerPin, NOTE_C4);
delay(1000);
noTone(speakerPin);
}
// play the champion melody
void melodyChampion() {
tone(speakerPin, NOTE_C4);
delay(300);
tone(speakerPin, NOTE_D4);
delay(300);
tone(speakerPin, NOTE_E4);
delay(300);
tone(speakerPin, NOTE_F4);
delay(300);
tone(speakerPin, NOTE_G4);
delay(300);
tone(speakerPin, NOTE_A4);
delay(300);
tone(speakerPin, NOTE_B4);
delay(300);
tone(speakerPin, NOTE_C5);
delay(300);
tone(speakerPin, NOTE_B4);
delay(300);
tone(speakerPin, NOTE_A4);
delay(300);
tone(speakerPin, NOTE_G4);
delay(300);
tone(speakerPin, NOTE_F4);
delay(300);
tone(speakerPin, NOTE_E4);
delay(300);
tone(speakerPin, NOTE_D4);
delay(300);
tone(speakerPin, NOTE_C4);
delay(1000);
noTone(speakerPin);
}
// run a self test loop, useful to test if the display and pins are hooked up correctly
void selfTestLoop() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("\x01\x02\x03");
while(true) {
lcd.setCursor(0, 1);
lcd.print("wire : ");
lcd.print(isWireTouched() ? "yes" : "no ");
lcd.setCursor(0, 2);
lcd.print("start : ");
lcd.print(isStartTouched() ? "yes" : "no ");
lcd.setCursor(0, 3);
lcd.print("end : ");
lcd.print(isEndTouched() ? "yes" : "no ");
}
}
/*************************************************
* Public Constants
*************************************************/
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
Comments