ブレッドボードからPCBへ:Simon Saysゲームの制作 – パート1
部品と用品
| 部品 | 数量 | 備考 |
|---|---|---|
| Arduino UNO | 1 | |
| はんだ付け不要ブレッドボード フルサイズ | 1 | |
| LED(汎用) | 4 | 緑・赤・黄・青 各1 |
| SparkFun プッシュボタンスイッチ 12mm | 4 | LEDと対応する色 |
| ブザー | 1 | |
| ジャンパーワイヤー(汎用) | 12 | |
| 抵抗 10kΩ | 4 | ボタン用プルダウン(内蔵プルアップ使用時は不要) |
| 抵抗 330Ω | 4 | LED電流制限用 |
| USB-A - Bケーブル | 1 |
アプリとオンラインサービス
- Arduino IDE
このプロジェクトについて
はじめに
誰もが知る「Simon Says」ゲーム:光るボタンのシーケンスを記憶し、同じ順序でボタンを押すアレです。Hackster LiveでPCB設計ツール「Upverter」を紹介するために、この楽しくシンプルなプロジェクトを作り、PCB化しました。以下はハードウェアとコードを含む基本プロジェクトです。
このシリーズは3部構成です。
- パート1: Simon Saysゲームの制作(本記事)
- パート2: UpverterでSimon SaysゲームのPCBを設計
- パート3: 設計したPCBをCNCで切削加工
このシリーズで学べること
- ブレッドボード上での基本的なプロジェクト配線
- UpverterでのPCBレイアウト
- CNCマシンでの自作PCB切削
ソフトウェア
Arduino IDEをお持ちでない方は、こちらから最新版をダウンロードしてください。
ハードウェアセットアップ
SparkFunのInventor's Kitの例を参考に、少しアレンジしたハードウェア構成です。以下のFritzing図をご覧ください。


コード
このゲームの面白さはバリエーションが無限に作れることです。ハードウェアはSparkFunの例をベースにし、コードはゼロから書きました。自作コードに興味がない方は、以下のコードを使うか、SparkFunの例題コードを少し修正して使うか、他のSimon Saysコードを探してみてください。
詳細なコメントとデバッグ用シリアル出力を入れているので、ゲーム実行中の動作をシリアルモニターで確認できます。動作動画は以下をご覧ください!
Simon Saysゲーム動画
※動画ではクリア条件を「連続5回正解」に設定しています。この数を変えれば難易度調整可能ですが、動画を短くするため5回にしました。
さて、ブレッドボードをPCBに変える準備が整いました! 次回「Breadboard to PCB パート2 – UpverterでPCB設計」でお会いしましょう。
コード
Simon Says Arduinoコード Arduino
int ledArray[] = {12, 9, 5, 2}; // ledArray[0]=緑, [1]=赤, [2]=黄, [3]=青
int buttonArray[] = {13, 10, 6, 3}; // buttonArray[0]=緑, [1]=赤, [2]=黄, [3]=青
int pinCount = 4;
int buzzer = 8;
int ledState = 0;
int gameState = 0;
#define NUMBERTOWIN 5 // クリアに必要な正解数(変更で難易度調整可)
int gameValues[NUMBERTOWIN];
int roundNum = 0;
unsigned long previousMillis = 0;
unsigned long interval1 = 500;
void setLed(int ledNum);
void displayClue(int roundNum);
boolean waitForInput(int buttonNum);
void setup() {
Serial.begin(9600);
Serial.println("setup");
for (int Pin = 0; Pin < pinCount; Pin++) {
pinMode(ledArray[Pin], OUTPUT);
}
for (int Pin = 0; Pin < pinCount; Pin++) {
pinMode(buttonArray[Pin], INPUT_PULLUP); // 内蔵プルアップ使用
}
randomSeed(analogRead(0));
}
void loop() {
if (gameState == 0) {
int button0 = digitalRead(buttonArray[0]);
int button1 = digitalRead(buttonArray[1]);
int button2 = digitalRead(buttonArray[2]);
int button3 = digitalRead(buttonArray[3]);
if (button0 && button1 && button2 && button3) {
pre_game();
} else {
Serial.println("button Pressed");
setLed(-1);
roundNum = 0;
delay(1000);
gameState = 1;
}
}
if (gameState == 1) gamePlay();
if (gameState == 2) {
delay(500);
winning_sound();
winDisplay(); winDisplay(); winDisplay();
loseDisplay();
Serial.println("winDisplay");
delay(1000);
gameState = 0;
}
if (gameState == 3) {
delay(500);
losing_sound();
loseDisplay(); loseDisplay(); loseDisplay();
Serial.println("loseDisplay");
delay(1000);
gameState = 0;
}
}
void pre_game() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval1) {
if (ledState == 0) { Serial.println("pre green"); setLed(0); ledState = 1; }
else if (ledState == 1) { Serial.println("pre red"); setLed(1); ledState = 2; }
else if (ledState == 2) { Serial.println("pre yellow"); setLed(2); ledState = 3; }
else if (ledState == 3) { Serial.println("pre blue"); setLed(3); ledState = 0; }
previousMillis = currentMillis;
}
}
void gamePlay() {
Serial.println("gamePlay");
for (int i = 0; i < NUMBERTOWIN; i++) {
gameValues[i] = floor(random(0, 4));
Serial.println(gameValues[i], DEC);
}
Serial.print("Starting Round "); Serial.println(roundNum, DEC);
for (int r = 0; r < NUMBERTOWIN; r++) {
displayClue(roundNum);
for (int i = 0; i <= roundNum; i++) {
Serial.print("Waiting for input "); Serial.print(i+1, DEC);
Serial.print(" of "); Serial.print(roundNum+1, DEC); Serial.println();
if (waitForInput(gameValues[i])) {
if (i == roundNum) {
Serial.println("Correct");
if (roundNum == NUMBERTOWIN - 1) {
Serial.println("You Win!");
gameState = 2;
return;
} else {
Serial.println("Continue");
}
}
} else {
Serial.println("You Lose!");
gameState = 3;
return;
}
}
roundNum++;
delay(1000);
}
}
void setLed(int ledNum) {
if (ledNum < 0) {
for (int i = 0; i < pinCount; i++) digitalWrite(ledArray[i], LOW);
} else {
for (int i = 0; i < pinCount; i++) {
digitalWrite(ledArray[i], (i == ledNum) ? HIGH : LOW);
}
}
}
void displayClue(int roundNum) {
setLed(-1);
for (int i = 0; i <= roundNum; i++) {
setLed(gameValues[i]);
delay(750);
setLed(-1);
delay(250);
}
}
boolean waitForInput(int buttonNum) {
while (true) {
int button0 = digitalRead(buttonArray[0]);
int button1 = digitalRead(buttonArray[1]);
int button2 = digitalRead(buttonArray[2]);
int button3 = digitalRead(buttonArray[3]);
if (!button0 || !button1 || !button2 || !button3) {
delay(250);
if (buttonNum == 0) { digitalWrite(ledArray[0], HIGH); delay(250); digitalWrite(ledArray[0], LOW); }
else if (buttonNum == 1) { digitalWrite(ledArray[1], HIGH); delay(250); digitalWrite(ledArray[1], LOW); }
else if (buttonNum == 2) { digitalWrite(ledArray[2], HIGH); delay(250); digitalWrite(ledArray[2], LOW); }
else if (buttonNum == 3) { digitalWrite(ledArray[3], HIGH); delay(250); digitalWrite(ledArray[3], LOW); }
if (buttonNum == 0 && button0 == 0) { Serial.println("0 Pressed"); return true; }
else if (buttonNum == 1 && button1 == 0) { Serial.println("1 Pressed"); return true; }
else if (buttonNum == 2 && button2 == 0) { Serial.println("2 Pressed"); return true; }
else if (buttonNum == 3 && button3 == 0) { Serial.println("3 Pressed"); return true; }
else return false;
}
}
}
void winDisplay() {
for (int i = 0; i < 4; i++) { digitalWrite(ledArray[i], HIGH); delay(75); digitalWrite(ledArray[i], LOW); delay(75); }
for (int i = 2; i >= 0; i--) { digitalWrite(ledArray[i], HIGH); delay(75); digitalWrite(ledArray[i], LOW); delay(75); }
}
void winning_sound() {
Serial.println("buzzer1");
tone(buzzer, 294, 250); delay(200);
tone(buzzer, 294, 250); delay(200);
tone(buzzer, 294, 250); delay(200);
tone(buzzer, 392, 500); delay(500);
tone(buzzer, 392, 250); delay(200);
tone(buzzer, 440, 250); delay(200);
tone(buzzer, 392, 250); delay(200);
tone(buzzer, 440, 250); delay(200);
tone(buzzer, 494, 500);
}
void loseDisplay() {
for (int i = 0; i < 4; i++) digitalWrite(ledArray[i], HIGH);
delay(200);
for (int i = 0; i < 4; i++) digitalWrite(ledArray[i], LOW);
delay(200);
}
void losing_sound() {
Serial.println("losing_sound");
tone(buzzer, 98, 250); delay(250);
tone(buzzer, 93, 250); delay(250);
tone(buzzer, 87, 250); delay(250);
}
回路図
simon_says_fritzing_Yb8EdKPqD4.fzz製造プロセス
- Arduino NanoとMPU-6050で作るリアルタイムジャイロスコープゲーム
- Arduinoデジタルダイス: LCD表示の乱数ジェネレーター自作
- Arduino Nanoで37LEDルーレットゲームを自作:ヨーロピアンスタイル完全再現
- DIY Arduino USBゲームコントローラー - 高性能ゲームパッドを自作
- Arduinoとジョイスティックでインタラクティブゲーム – LEDフィードバック付き
- ポータブル距離検出器:Arduino Nano自作キット(HC-SR04、18650電源、3Dプリントケース付き)
- Pixel Chaser: Arduino Nanoで作るワンタップLEDゲーム
- 銅メッキプロジェクト:Arduino UNOで作るスマート電気メッキシステム
- Arduino Nanoで作るNeoPixelマトリックス版Pongゲーム
- 中小ショップのための航空宇宙製造参入ガイド:実践的アプローチ
- 4層PCB製造完全ガイド:ステップバイステッププロセス(後編)