迷路ゲーム

こんにちは!PIC MANです.

以前作成したProcessingとArduino,加速度センサを用いた「迷路ゲーム」の仕組みについて解説したいと思います.

迷路ゲームについて

迷路ゲームは,その名の通り迷路を使った2種類のゲームが楽しめる作品になります.
一つは迷路の中のボール(右下の灰色の球)をゴール(左上の赤の部分)までいかに早く持っていくかを競うゲームです.

もう一つは迷路の中にある得点(青丸)を多く集めるゲームです.

どちらのゲームも下のようなコントローラを傾けることでボールを操作します.Arduinoに加速度センサ,3つのスイッチが付いてます.

迷路ゲームの仕組み

迷路ゲームでは次のソフトウェア・ハードウェアを使って構成されています.

  • Processing
  • Arduino
  • 加速度センサADXL345
  • タクトスイッチ
  • 基板,配線材

ゲームの本体のソフトウェアはProcessingを使って作りました.またコントローラはArduinoと加速度センサを用いてます.
加速度センサを使い,重力のかかっている方向を検出することでコントローラの傾き具合を判断し,ボールを動かすことができます.
また測定された傾き具合はSerial通信を介してパソコン上のProcessingに送られます.

ハードウェア

コントローラの回路は図のようになっています.

回路はシンプルです.加速度センサとArduinoはI2Cと呼ばれる規格で通信させています.加速度センサADXL345上にはI2C通信に使うデータ線路上に必要なプルアップ抵抗がすでに組み込まれているため接続不要です.またタクトスイッチの部分もArduino内部でプルアップさせているためプルアップ抵抗は不要です.

ArduinoのプログラムはPCから命令を受け取ると加速度センサADXL345から3軸の加速度データをもらい,PCへ送信するような仕組みになっています.
加速度センサADXL345との通信の部分はこちらのサイトを参考にさせていただきました.
プログラムは下のようになります.

#include <Wire.h>;

#define RESET_BTN 2
#define YELLOW_BTN 3
#define BLUE_BTN 4
#define DEVICE_ADDR (0x53) // スレーブデバイスのアドレス

byte axis_buff[6];

void setup()
{
    Serial.begin(9600); // シリアルの開始
    Wire.begin(); // I2Cの開始
    // DATA_FORMAT
    writeI2c(0x31, 0x00);
    // POWER_TCL
    writeI2c(0x2d, 0x08);

    // タクトスイッチ入力ピンの設定
    pinMode(RESET_BTN, INPUT_PULLUP);
    pinMode(YELLOW_BTN, INPUT_PULLUP);
    pinMode(BLUE_BTN, INPUT_PULLUP);
}

void loop()
{
    // S が飛んできたら送る
    char c =Serial.read();
    uint8_t command = 0;
    static bool sw_state[3] = {1,1,1};
    
    if(c == 'S')
    {
        uint8_t length = 6;
        readI2c(0x32, length, axis_buff); //レジスターアドレス 0x32から6バイト読む
        int x = (((int)axis_buff[1]) << 8) | axis_buff[0];
        int y = (((int)axis_buff[3]) << 8) | axis_buff[2];
        int z = (((int)axis_buff[5]) << 8) | axis_buff[4];
        
        if(digitalRead(RESET_BTN) && !sw_state[0]){
            command = 1;
        } else if(digitalRead(YELLOW_BTN) && !sw_state[1]){
            command = 2;
        } else if(digitalRead(BLUE_BTN) && !sw_state[2]){
            command = 3;
        }
        // 送信
        char str[32];
        sprintf(str, "%d,%d,%d,%d,\n", x, y, z, command);
        Serial.print(str);
        sw_state[0] = digitalRead(RESET_BTN);
        sw_state[1] = digitalRead(YELLOW_BTN);
        sw_state[2] = digitalRead(BLUE_BTN);
    }
}

// I2Cへの書き込み
void writeI2c(byte register_addr, byte value)
{
    Wire.beginTransmission(DEVICE_ADDR);
    Wire.write(register_addr);
    Wire.write(value);
    Wire.endTransmission();
}

// I2Cへの読み込み
void readI2c(byte register_addr, int num, byte buffer[])
{
    Wire.beginTransmission(DEVICE_ADDR);
    Wire.write(register_addr);
    Wire.endTransmission();
    Wire.beginTransmission(DEVICE_ADDR);
    Wire.requestFrom(DEVICE_ADDR, num);

    int i = 0;
    while(Wire.available())
    {
        buffer[i] = Wire.read();
        i++;
    }
    Wire.endTransmission();
}

このプログラムではメインのループ部分にて,PC側からSerial通信で大文字のSが送られてくると加速度のデータを取得し,またタクトスイッチの状態データとともにPCへ送信を行います.
タクトスイッチの状態についてですが,ボタンが押された瞬間だけを認識してフラグを立てたいので,ワンショット回路のようなものをソフトウェアで構成させています.ワンショット回路とはスイッチの入力が切り替わった場合に1を出力するような回路です.

ソフトウェア

先に述べたようにゲームの本体はProcessingを使って作りました.

核となるのは迷路を生成する部分と物理演算エンジンを用いたところです.迷路の生成には棒倒し法や穴伸ばし法,壁伸ばし法など様々な手法が存在しますが今回は穴掘り法を用いたこちらのサイトを参考にさせていただきました.

物理演算エンジンにはBox2dを使用しました.Processing用に移植されたものですがサンプルも多くよく利用されています.物理演算エンジンを用いることで迷路のフィールド上に傾きを与え,ボールを転がしたり,壁にぶつけて跳ね返させたりすることができます.

また,本プログラムではメインのゲームウィンドウと別にデバッグ用のウィンドウを用意しています.

SerialPortの選択やソフトウェア上からボタンの操作ができます.また加速度の生の値などを確認できます.さらに迷路のサイズ(複雑さ)や得点ゲーム集めにおけるポイントの数なども調節できます.

Prosessingのソースコードは私のGitHubに公開しています。

PIC MAN

ソフトとハードの両方の目線を持てるようになりたいです.

おすすめ

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です