아두이노 우노로 만드는 닌자 달러 LCD 게임
부품 및 소모품
| 부품 | 수량 | 비고 |
| 아두이노 UNO | 1 | |
| Adafruit 표준 LCD 16x2 (흰글자/파란배경) | 1 | |
| 브레드보드 | 2 | 여유 공간 위해 2개 사용, 1개로도 가능 |
| 단회전 포텐셔미터 10kΩ | 1 | LCD 대비 조절용 |
| LED (범용) | 2 | 점프/슈팅 표시용 |
| 저항 1kΩ | 4 | LED 전류 제한용 |
| SparkFun 푸시버튼 스위치 12mm | 2 | 점프/슈팅 버튼 |
| RobotGeek 부저 | 1 | 효과음용 |
| 점퍼 와이어 | 1세트 | |
필요 도구
프로젝트 소개
간단한 LCD 게임입니다. 구글 크롬의 공룡 게임에서 영감을 받아 몇 가지 변화를 주었습니다. 달러 전사가 끊임없이 이동하며 장애물을 피하고 '별' 포인트를 획득합니다. 장애물을 뛰어넘으면 1점, 별을 잡으면 5점을 얻습니다. 전사는 총을 쏴 앞의 장애물을 제거할 수도 있습니다. 점프/슈팅 여부를 LED로 표시합니다. 10, 20, 30점 달성 시 이동 속도가 빨라지며, 50점 달성 시 승리, 장애물 충돌 시 패배입니다. 이 경계값은 코드에서 쉽게 변경 가능합니다. 패시브 부저로 점프/슈팅 시 효과음, 승패 시 멜로디를 재생합니다. 첫 프로젝트인데 마음에 드셨으면 좋겠습니다. 댓글과 리뷰 부탁드립니다.
영상
(영상 링크)
연결 방법
LCD 모듈 하단에 16핀 수 헤더가 있습니다. 사진처럼 브레드보드에 꽂으세요. LCD를 제어하고 전원을 공급하는 모든 신호가 이 헤더를 통해 들어갑니다.
핀 배열(왼쪽부터 오른쪽):
- GND - 전원 그라운드
- VCC - 양전원
- V0 - 대비 조절
- RS - 레지스터 선택
- R/W - 읽기/쓰기 선택
- E - 인에이블 신호
- D0~D3 - 데이터 비트 0~3 (본 프로젝트에서 미사용)
- D4~D7 - 데이터 비트 4~7
- A - 백라이트 LED 양극
- K - 백라이트 LED 음극
아두이노 5V를 브레드보드 상단 빨간 라인에, GND를 파란 라인에 점퍼 와이어로 연결하세요.
- VSS → 그라운드
- VDD → 5V
- V0 → 포텐셔미터 출력 핀
- RS → 아두이노 핀 12
- RW → 그라운드
- E → 아두이노 핀 11
- D4 → 아두이노 핀 5
- D5 → 아두이노 핀 4
- D6 → 아두이노 핀 3
- D7 → 아두이노 핀 2
- A → 5V
- K → GND
포텐셔미터 나머지 핀들을 5V와 GND에 연결하세요.
3핀 피에조 부저면 S핀을 아두이노 7번, '-'핀을 GND, 나머지 핀을 5V에 연결하세요. 2핀이면 한 핀을 GND, 다른 핀을 아두이노 7번에 연결하세요.
버튼은 회로도대로 연결하세요. 첫 번째 버튼(점프)은 아두이노 1번, 두 번째(슈팅)는 6번 핀에 연결합니다. LED는 버튼만으로 제어되며 아두이노와 무관합니다. 애노드를 아두이노 연결된 버튼 핀에, 캐소드를 그라운드에 연결하세요.
코드
dollar_warrior (Arduino)
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
const int buttonPin1 = 1;
const int buttonPin2 = 6;
const int buzzer = 7;
unsigned long pts = 0;
bool buttonState1 = 0;
bool buttonState2 = 0;
int randomNums[6];
int randomNum = 0;
int randomNums1[3];
int randomNum1 = 0;
unsigned int myDelay = 500;
bool temp = 0;
int tempI[16];
bool temp1 = 0;
int tempI1[3];
int button2IsPressed = 0;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16, 2);
pinMode(buttonPin1, INPUT);
pinMode(buttonPin2, INPUT);
pinMode(buzzer, OUTPUT);
lcd.setCursor(4, 0);
lcd.print("THE GAME");
lcd.setCursor(2, 1);
lcd.print("STARTS IN ");
lcd.print("5");
delay(1000);
lcd.setCursor(12, 1);
lcd.print("4");
delay(1000);
lcd.setCursor(12, 1);
lcd.print("3");
delay(1000);
lcd.setCursor(12, 1);
lcd.print("2");
delay(1000);
lcd.setCursor(12, 1);
lcd.print("1");
delay(1000);
lcd.clear();
}
void loop() {
here:
randomNum = random(5);
for (int i = 0; i < randomNum; ++i) {
randomNums[i] = random(16);
}
randomNum1 = random(3);
for (int i = 0; i < randomNum1; ++i) {
randomNums1[i] = random(16);
}
temp = 0;
for (int j = 0; j < 3; ++j) {
tempI1[j] = 0;
}
button2IsPressed = 0;
for (int i = 0; i < 16; ++i) {
// 점수 표시
if (pts > 9 && pts < 20) {
lcd.setCursor(14, 0);
myDelay = 400;
} else if (pts > 19 && pts < 30) {
lcd.setCursor(14, 0);
myDelay = 300;
} else if (pts > 29 && pts < 50) {
myDelay = 200;
lcd.setCursor(14, 0);
} else if (pts >= 50) {
pts = 0;
myDelay = 500;
lcd.clear();
lcd.setCursor(5, 0);
lcd.print("VICTORY");
tone(buzzer, 262); delay(200);
tone(buzzer, 330); delay(200);
tone(buzzer, 392); delay(100);
tone(buzzer, 330); delay(100);
tone(buzzer, 392); delay(100);
tone(buzzer, 523); delay(200);
noTone(buzzer);
delay(3000);
lcd.clear();
goto here;
} else {
lcd.setCursor(15, 0);
}
lcd.print(pts);
buttonState1 = digitalRead(buttonPin1);
buttonState2 = digitalRead(buttonPin2);
// 장애물 표시
if (!temp) {
for (int j = 0; j < randomNum; ++j) {
lcd.setCursor(randomNums[j], 1);
lcd.print("#");
}
} else {
for (int j = 0; j < randomNum; ++j) {
if (tempI[0] > randomNums[j]) {
lcd.setCursor(randomNums[j], 1);
lcd.print("#");
}
}
}
// 포인트(별) 표시
if (!temp1) {
for (int j = 0; j < randomNum1; ++j) {
lcd.setCursor(randomNums1[j], 0);
lcd.print("*");
}
} else {
for (int j = 0; j < randomNum1; ++j) {
if (randomNums1[j] != tempI1[j]) {
lcd.setCursor(randomNums1[j], 0);
lcd.print("*");
}
}
}
// 점프 버튼
if (buttonState1 == HIGH) {
lcd.setCursor(i, 0);
tone(buzzer, 131);
delay(200);
noTone(buzzer);
} else {
lcd.setCursor(i, 1);
}
lcd.print("$");
// 슈팅 버튼
if (buttonState2 == HIGH) {
tone(buzzer, 175);
delay(100);
noTone(buzzer);
temp = 1;
if (buttonState1 == LOW) {
tempI[button2IsPressed] = i;
}
++button2IsPressed;
for (int k = i + 1; k < 16; ++k) {
if (buttonState1 == LOW)
lcd.setCursor(k, 1);
else
lcd.setCursor(k, 0);
lcd.print("~");
delay(5);
if (buttonState1 == LOW)
lcd.setCursor(k - 1, 1);
else
lcd.setCursor(k - 1, 0);
lcd.print(" ");
delay(5);
}
}
delay(myDelay);
lcd.clear();
// 별 획득 체크
for (int j = 0; j < randomNum1; ++j) {
if (i == randomNums1[j] && buttonState1 == HIGH) {
temp1 = 1;
tempI1[j] = i;
pts += 5;
}
}
// 장애물 충돌 체크
for (int j = 0; j < randomNum; ++j) {
if (i == randomNums[j] && buttonState1 == LOW && temp == 0) {
pts = 0;
myDelay = 500;
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("GAME");
lcd.setCursor(6, 1);
lcd.print("OVER");
tone(buzzer, 349); delay(200);
tone(buzzer, 277); delay(200);
tone(buzzer, 220); delay(100);
tone(buzzer, 277); delay(100);
tone(buzzer, 220); delay(200);
noTone(buzzer);
delay(3000);
lcd.clear();
goto here;
} else if (i == randomNums[j] && buttonState1 == HIGH) {
++pts;
}
}
}
}
회로도
game_aUIjA6VZxX.fzz