コントローラー組み立てガイド
クレーンゲーム コントローラーの配線とプログラムをまとめています。 Arduino Pro Micro(ATmega32U4)を使い、ブレッドボード上で組み立てます。
1. 回路構成
配線表
| 接続先 | Pro Micro ピン |
|---|---|
| 7セグ TM1637 — CLK | D2 |
| 7セグ TM1637 — DIO | D3 |
| 投下ボタン | D4 |
| スタートボタン | D5 |
| LED(220Ω 経由) | D6 |
| ジョイスティック VRX(X軸) | A0 |
| ジョイスティック VRY(Y軸) | A1 |
| 電源 +(7セグ・ジョイスティック) | VCC |
| GND(7セグ・ジョイスティック・ボタン・LED) | GND |
Pro Micro ピン配置(使用ピンを赤で表示)
ブレッドボード回路図
メモ
- 各パーツの端子の並び順(CLK / DIO / VCC / GND など)は、製品によって異なる場合があります。必ず実物に印刷された文字を見て繋いでください。この図の並び順はあくまで一例です。
- 今回はブレッドボード上での再現でOKです。本番の筐体では、各ボタン・スティックの設置位置が離れるため、配線ケーブルが長くなります。
- VCC と GND はブレッドボードの電源レール(+/−)に繋ぎ、そこから 7セグとジョイスティックに分配します。
- ボタンは INPUT_PULLUP 方式のため、片側を信号ピン、反対側を GND に繋ぎます(外付け抵抗は不要)。
- LED には抵抗を必ず挟んでください。220Ω が目安ですが、手持ちがなければ 220Ω 以上でもOKです(明るさが少し落ちる程度)。アノード=長い足が D6 側、カソード=短い足が GND 側。
2. プログラミング
ゲームの流れ
係員が Start を押すと1ラウンド開始。Drop ボタン押下、または 30秒経過で強制的に投下し、待機に戻ります。 これを繰り返します(3回で1プレイ)。
実装のヒント
コントローラー班が書きはじめたコード(Is_game / Timer)をベースに、全体の流れ(loop の骨格)と、必要な部品(関数)をまとめました。
まず「全体像」で loop が何をするかを掴んでから、①〜④の部品を用意して loop に書き込んでいくと分かりやすいです。
全体像:loop の流れ
これが骨格です。コメントの各処理を、下の①〜④の部品を使って書き込んでいきます。
void loop() {
if (!Is_game) {
// 【待機】
// Start が押されたら(②の justPressed を使う):
// Keyboard.write(KEY_RETURN); // Enter送信
// Timer = 30; lastTick = millis();
// digitalWrite(LED_DROP, HIGH); // LED点灯
// Is_game = true;
// ※ ジョイスティックは送らない(操作を受け付けない)
} else {
// 【プレイ中】
// 1) ④のカウントダウン処理を書く(Timer=0 なら投下へ)
// 2) ③のジョイスティック → WASD を書く(setKey を4方向ぶん)
// 3) Drop が押された(②)or Timer=0 → 投下:
// Keyboard.write(' '); // Space送信
// keyW/keyA/keyS/keyD を全部 release
// digitalWrite(LED_DROP, LOW); // LED消灯
// Is_game = false; // 待機に戻る
}
}
① ピン定義・状態変数・setup
#include <TM1637Display.h>
#include <Keyboard.h>
#define CLK 2
#define DIO 3
#define BTN_DROP 4
#define BTN_START 5
#define LED_DROP 6
#define JOY_X A0
#define JOY_Y A1
#define THRESHOLD_LOW 300
#define THRESHOLD_HIGH 700
bool Is_game = false; // プレイ中か
int Timer = 30; // 残り秒数
unsigned long lastTick = 0; // カウントダウン用
TM1637Display display(CLK, DIO);
void setup() {
pinMode(BTN_DROP, INPUT_PULLUP);
pinMode(BTN_START, INPUT_PULLUP);
pinMode(LED_DROP, OUTPUT);
display.setBrightness(7);
display.showNumberDec(0);
Keyboard.begin();
delay(2000); // 暴走対策:起動後すこし待つ
}
② ボタンの「押された瞬間」を検出(チャタリング対策込み)
機械式ボタンは押した瞬間に信号が細かくバタつきます(チャタリング)。 「一度変化したら少しの間は無視する」ことで防ぎます。これを使うと、押しっぱなしでも1回だけ反応します。
const unsigned long DEBOUNCE = 30; // ms
// pin が押された瞬間だけ true を返す(チャタリング対策込み)
// stableLow=安定状態, lastChange=最後に変化した時刻(ボタンごとに用意)
bool justPressed(int pin, bool &stableLow, unsigned long &lastChange) {
bool reading = (digitalRead(pin) == LOW); // 押すと LOW
if (reading != stableLow && millis() - lastChange > DEBOUNCE) {
lastChange = millis();
stableLow = reading;
if (stableLow) return true; // HIGH→LOW = 押された瞬間
}
return false;
}
// ボタンごとに状態をグローバルに用意する:
// bool startLow = false, dropLow = false;
// unsigned long startChg = 0, dropChg = 0;
// 使うとき:if (justPressed(BTN_START, startLow, startChg)) { ... }
③ ジョイスティック → WASD(押した間だけ送る)
倒した瞬間に press、戻した瞬間に release。これでキーが押しっぱなしで固まりません。
bool keyW = false, keyA = false, keyS = false, keyD = false;
// 倒した瞬間に press、戻した瞬間に release
void setKey(char key, bool &state, bool wantPress) {
if (wantPress && !state) { Keyboard.press(key); state = true; }
else if (!wantPress && state) { Keyboard.release(key); state = false; }
}
// プレイ中に呼ぶイメージ:
// int x = analogRead(JOY_X); int y = analogRead(JOY_Y);
// setKey('w', keyW, y > THRESHOLD_HIGH); // 上 …これを4方向ぶん
④ カウントダウンは millis() で(delay を使わない)
delay(1000) を使うと、その1秒間ジョイスティックやボタンが反応しません。millis() で「1秒経ったら減らす」方式にします。
// 「プレイ中」の中で呼ぶ。1秒ごとに Timer を1減らす
if (millis() - lastTick >= 1000) {
lastTick += 1000;
Timer--;
display.showNumberDec(Timer);
if (Timer <= 0) {
// ここに「時間切れ = 強制投下」の処理を書く
}
}
ここから仕上げるポイント
- しきい値(THRESHOLD)を実機で調整:ジョイスティックの個体差で中央値がズレるので、実際の値を見て微調整する
- 本番ゲーム(Unity)との接続確認:WASD / Space / Enter が正しく届くか、デバッグ用サイトで確認する
- LED の発展:将来は「投下後に3秒点滅 → 消灯」などの演出も追加できる
- ベルは手動:景品が取れたら係員が手動でベルを鳴らす運用。コントローラー側の電子工作は不要
このあとの流れ
コントローラーが組めたら、テストページで「キー入力が正しく届くか」「クレーンが操作できるか」を確認してください。本番ゲームができる前の動作チェックに使えます。
コントローラーをテストする →