工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduinoで作るスネークゲーム:8×8 LEDマトリクスとジョイスティックでレトロゲーム機自作

必要な部品と材料

部品数量
Arduino UNO1
Arduino Proto Shield1
8×8 LEDマトリクス(単色、MAX7219ドライバ搭載推奨)1
アナログジョイスティック(汎用)1
ジャンパーワイヤー(オス/メス)1セット

使用ツール

プロジェクト概要

Meccanoid/Erectorセットのフレームを使い、Sergey Royz氏のコードをベースにスネークゲームを実装。速度調整で滑らかな動作を実現しました。フレーム製作は各自で工夫してください。

配線図

Proto ShieldをArduino Unoに装着し、GND/5Vを拡張。ブレッドボード不要で配線できます。

LEDマトリクス接続(MAX7219モジュールの場合)

ジョイスティック接続

スケッチ(全文)

/**
 * Snake Game for 8x8 LED Matrix
 * Based on Sergey Royz's implementation
 * Modified by hunter Buzzell
 */
#include <LedControl.h>

#define VRX A0
#define VRY A1
#define SW 2
#define CLK 8
#define CS 9
#define DIN 10
#define SIZE 8
#define ADVANCE_DELAY 20

int snake[SIZE*SIZE][2];
int length;
int food[2], v[2];
bool is_game_over = false;
long current_time, prev_advance;
int blink_count;
const short messageSpeed = 5;

LedControl lc = LedControl(DIN, CLK, CS, 1);

void init_game() {
  prev_advance = current_time = 0;
  blink_count = 3;
  int half = SIZE / 2;
  length = SIZE / 3;
  for (int i = 0; i < length; i++) {
    snake[i][0] = half - 1;
    snake[i][1] = half + i;
  }
  food[0] = half + 1;
  food[1] = half - 1;
  v[0] = 0; v[1] = -1;
}

void render() {
  for (int i = 0; i < length; i++) {
    lc.setLed(0, snake[i][0], snake[i][1], 1);
  }
  lc.setLed(0, food[0], food[1], 1);
}

void clearScreen() {
  for (int x = 0; x < SIZE; x++)
    for (int y = 0; y < SIZE; y++)
      lc.setLed(0, x, y, 0);
}

bool advance() {
  int head[2] = {snake[0][0] + v[0], snake[0][1] + v[1]};
  if (head[0] < 0 || head[0] >= SIZE || head[1] < 0 || head[1] >= SIZE) {
    delay(1000); showGameOverMessage(); return true;
  }
  for (int i = 0; i < length; i++) {
    if (snake[i][0] == head[0] && snake[i][1] == head[1]) {
      delay(1000); showGameOverMessage(); return true;
    }
  }
  bool grow = (head[0] == food[0] && head[1] == food[1]);
  if (grow) {
    length++;
    randomSeed(current_time);
    food[0] = random(SIZE);
    food[1] = random(SIZE);
  }
  for (int i = length - 1; i >= 0; i--) {
    snake[i + 1][0] = snake[i][0];
    snake[i + 1][1] = snake[i][1];
  }
  snake[0][0] += v[0];
  snake[0][1] += v[1];
  return false;
}

void setup() {
  pinMode(SW, INPUT_PULLUP);
  pinMode(VRX, INPUT);
  pinMode(VRY, INPUT);
  attachInterrupt(digitalPinToInterrupt(SW), restart, RISING);
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);
  init_game();
  render();
}

void loop() {
  if (!is_game_over) {
    clearScreen();
    render();
    if (current_time - prev_advance > ADVANCE_DELAY) {
      is_game_over = advance();
      prev_advance = current_time;
    }
  } else {
    while (blink_count > 0) {
      clearScreen(); delay(300);
      render(); delay(300);
      blink_count--;
    }
  }
  readControls();
  current_time++;
}

void restart() {
  init_game();
  is_game_over = false;
}

void readControls() {
  int dx = map(analogRead(VRX), 0, 906, 2, -2);
  int dy = map(analogRead(VRY), 0, 906, -2, 2);
  if (dx != 0) dx = dx / abs(dx);
  if (dy != 0) dy = dy / abs(dy);
  if (dy != 0 && v[0] != 0) { v[0] = 0; v[1] = dy; }
  if (dx != 0 && v[1] != 0) { v[0] = dx; v[1] = 0; }
}

const PROGMEM bool gameOverMessage[8][90] = {
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}
};

void showGameOverMessage() {
  for (int d = 0; d < sizeof(gameOverMessage[0]) - 7; d++) {
    for (int col = 0; col < 8; col++) {
      delay(messageSpeed);
      for (int row = 0; row < 8; row++) {
        lc.setLed(0, row, col, pgm_read_byte(&(gameOverMessage[row][col + d])));
      }
    }
  }
}

LedControlライブラリが必要です(ライブラリマネージャからインストール可能)。ジョイスティックのアナログ値を読み取り、スネークの移動方向を制御します。ゲームオーバー時は「GAME OVER」メッセージをスクロール表示。

製造プロセス

  1. DIY Arduino USBゲームコントローラー - 高性能ゲームパッドを自作
  2. Arduino NanoとMAX7219で作る24×16 LEDポングゲーム機
  3. 自作16×8 LEDマトリックスでテトリスゲーム:Arduino Nano実装
  4. ArduinoでBluetooth経由でLEDを制御 – シンプルDIYガイド
  5. PIRセンサー連動 インタラクティブLEDマトリクスドアディスプレイ - ホリデーグリーティング
  6. スマートArduino四足歩行ロボットの製作:ステップバイステップガイド
  7. Pixel Chaser: Arduino Nanoで作るワンタップLEDゲーム
  8. Arduino Nanoで作る8×8 LEDマトリックスのフリップクロック - 自作リアルタイムクロック
  9. Arduino RGB LEDカラーミキサー:初心者向けDIYプロジェクト
  10. Arduino Unoで8×8 LEDマトリックスを制御:ステップバイステップガイド
  11. Arduino NanoとWS2812 LEDストリップで作る1次元ポンゲーム - 完全DIYガイド