大阪電気通信大学

『Maybe Bread』 RFIDとM5Stickを用いたゲーム制作


ゲーム内容

「パン屋で働こう!」

現実世界で選んだものをNFCを通してゲーム内に反映させます。プレイヤーは様々な調味料を組み合わせたり、火加減を調整したりしてお客さんの望むパンを完成させることを目的としたゲームです。

制作経緯

ボタンやマウスの操作だけでなく、実際に調理をしている感覚を楽しむことのできる料理ゲームを作りたいと考えました。そこでNFCを用いることで自分の手で調味料を選択する動作やデバイスでの操作を加えることを可能にし、現実と仮想とが融合するゲームの実現を目指しました。


操作画面


デバイス

操作に使用するデバイスにはM5StickCPlus2を使用しました。RFIDタグは小型で薄いものを使用しています。

ーー マイコン M5StickCPlus2

ESP-32が搭載されたマイコンボードで、6軸センサー(IMU)やマイク、ブザーや液晶などがついています。Wi-fi・Bluetoothに対応しており、ユニットと呼ばれるセンサーを繋げることで機能を拡張することができます。今回はRFIDタグを使用するためにRFID読み取りユニットを接続しました。

M5とRFIDユニット

ーー 書き込みツール Arduino IDE

M5StickCPlus2にプログラム(スケッチ)を書き込むためにArduino IDEというソフトを使用しました。書き込みをする前の準備段階としてポートの確認やボードの設定を行いました。C言語をベースにしたArduino言語です。

ーー RFIDタグ

円形で厚さが薄いRFIDタグを瓶の底に貼っています。このRFIDタグのそれぞれに割り当てられているUIDという個体識別用の文字列を判別することで、どの瓶が読み込まれたのかが分かるようになっています。UIDはUnityに紐づけられているExcelで管理しており、タグの交換や追加が容易にできるようにしています。

ExcelでUIDを管理

見た目が全て同じであるため、混ざらないようにマスキングテープでどれと対応しているのかを分かりやすくしています。

ーー RFIDを貼り付ける瓶

ゲーム内のパンの素材の数と同量の瓶を用意する必要がありました。そこで製作費を抑えるために100円均一で全て材料を揃えました。瓶には紙製のラベルを貼っています。ラベルは味の種類と素材の名前のみのシンプルなデザインにしました。種類ごとに色分けし、瓶ごとに中身を変えています。

ーー 3Dプリンターで制作したデバイス用のケース

M5StickCPlus2を格納するためのケースを3Dプリンターで制作しました。

魔法の杖をイメージしてデザインしたものを、ナガタ先生に協力していただきながらFusion360を使用して3Dプリンター用のデータを作成しました。

ゼミ室の3Dプリンターで印刷を複数回行い、上手く出力できたパーツを組み合わせて完成させました。デバイスを格納した状態で組み立てることができるように、リューターや歯科用器具などを使ってサポートフィラメントを取り除きました。

システム

ゲームやデバイスに使用しているプログラムを一部紹介します。以下は、主に外部アセットやライブラリを活用している箇所です。

ーー Arduino IDE

M5StickCPlus2に書き込んだスケッチです。RFIDユニットを扱うためのライブラリ「MFRC522_I2C.h」というライブラリとBluetoothでシリアル通信を行うためのライブラリ「BluetoothSerial.h」を追加しています。

Bluetoothシリアル通信の送受信をする関数(通信テストで使用)

シリアル通信を通してUnityへ、データをBluetoothと有線両方で送信しています。有線/無線接続の切り替えはUnityで行っています。現在はM5からUnityへの一方向のみを使用していますが、UnityからM5にシリアル通信を送ることも可能です。

デバイスの縦振りを検知する関数

6軸センサを使い、デバイスの傾きと加速度からデバイスの動きを判定しています。6軸センサはM5Stick CPlus2自体に搭載されているものなので、外部から特別なライブラリを追加せずに実装することができます。検知した動きから規定の値に達しているかを確認し、有線/無線の両方でシリアル通信を使用しデータを送信しています。

UIDを読み取りシリアル通信でUIDを送信

RFIDタグから個々に割り当ているUIDを読み込み、有線/無線の両方でシリアル通信を行い送信します。UIDを送った後に少し間を開けて空白を送ることで、Unityとのスピードを調節し処理しやすくしています。

Bluetoothシリアル通信でM5StickCPlus2からUnityにUIDを送信している様子(動画)
実際のスケッチ
#include <M5Unified.h>
#include <BluetoothSerial.h>
#include <MFRC522_I2C.h>
#include "M5StickCPlus2.h"


#define UPPER_LIMIT 230.0 //ジャイロXの上判定ライン
#define LOWER_LIMIT -230.0 //ジャイロXの下判定ライン

float gyroX = 0.0f;
float gyroY = 0.0f;
float gyroZ = 0.0f;
int upCount = 0;
bool isShaked = false;

const uint8_t buttonA_GPIO = 37;

BluetoothSerial BTSerial;
MFRC522_I2C mfrc522_i2c(0x28, 2);
static String data = "";

void read_rfid(){
  String s = "";
  
  if (mfrc522_i2c.PICC_IsNewCardPresent() && mfrc522_i2c.PICC_ReadCardSerial()) {
    for (size_t i = 0; i < mfrc522_i2c.uid.size; ++i) {
      const auto d = mfrc522_i2c.uid.uidByte[i];
      s += String(d < 0x10 ? "0" : "") + String(d, HEX);
      
    }
    //BTSerial.println(s);
    s.toUpperCase();
  }
  if (s == "") {
    ::delay(200);
    return;
  }
  data = s;
  M5.Lcd.println(data);
  BTSerial.println(data);
  Serial.println(data);
  delay(200);
  BTSerial.println("");
  Serial.println("");

}

void read_serial(){
  if(BTSerial.available()){ //Bluetoothデータ受信で
    String msg = BTSerial.readString(); //BTシリアルで送られてきた文字列をmsgに格納
    M5.Lcd.println("Received: " + msg); //M5Stickの画面に文字列msgを表示
    //BTSerial.print(msg);  //BTシリアルに受け取ったmsgを送信

  }
}

void getShaked(){
  auto imu_update = M5.Imu.update();
  if(imu_update){
    M5.Imu.getGyro(&gyroX, &gyroY, &gyroZ);

    if(gyroX >= UPPER_LIMIT){
      upCount++;
    }

    if(gyroX <= LOWER_LIMIT && upCount > 0){
      upCount = 0;
      isShaked = true;
    }

    if(isShaked){
      BTSerial.println("Shaked");
      Serial.println("Shaked");
      delay(50);
      BTSerial.println("");
      Serial.println("");
      isShaked = false;
    }
    else { return; }
  }
}

void setup() {
  // put your setup code here, to run once:
  M5.begin();
  M5.Imu.init();
  M5.Lcd.setTextFont(1);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.println("BTSerial, RFID, sample! :D");
  BTSerial.begin("M5StickCPlus2BT");
  Serial.begin(115200);
  M5.Ex_I2C.begin();
  mfrc522_i2c.PCD_Init();

  attachInterrupt(digitalPinToInterrupt(buttonA_GPIO), buttonA_isr, FALLING);
}

void loop() {
  // put your main code here, to run repeatedly:
  //M5.update();
  //getButton();
  
  read_rfid();
  read_serial();
  getShaked();
  
}

ーー Unity

Unityで使用しているスクリプトの一部です。外部アセット/スクリプトとしてExcel Impoter、Dotween、lilToon、SerialHandler.cs、その他エフェクトを使用しています。このゲームの中で素材ごとのデータをまとめて管理するためにExcelを使用し、外部アセットを活用することでスクリプトで参照できるようになっています。

Dotween

画面に動きをつけるために導入しました。ちょっとしたテキストに動きをつけることで画面が静かになりすぎないようにしています。上の動画では「Please Shake Stick!!」と表示されている部分に使用しています。

lilToon

左:lilToon 右:デフォルト

ゲームの雰囲気にオブジェクトの見た目を変えるために使用しました。輪郭線やリムライトなど細かく設定しています。

Excel Impoter

Excel
Unity

パンの素材のデータをExcelで管理し、Unityに流し込むために導入しています。導入後は紐づいているExcelが更新されると自動で読み込み直してくれます。GameManagerスクリプトだけがアクセスするようにするようにしています。

SerialHandler.cs

Unityでシリアル通信に対応するためのスクリプトです。シリアル通信の送受信、M5StickCPlus2とデータをやり取りするために使用しています。2025年1月末時点では有線/無線を環境に合わせて手動で変更しています。インターネット上で公開されているものをそのまま使用すると、シーン遷移後に通信が切れてしまうのでシングルトンパターンを取り入れています。

具体的には1つのシーン内に非破壊Managerオブジェクトが1つのみ存在するようにし、シーン遷移後にManagerオブジェクトが2つ以上になった場合新たに生成された方を削除するようになっています。これにより再生したシーンに存在する非破壊Managerオブジェクトが再生終了までシーンを超えて存在し続け、別シーンでも重複しないようになりました。

シングルトンパターン用スクリプト

public class GMSingleton : MonoBehaviour
{
    public static GMSingleton instance;
    private void Awake()
    {
        if(instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            gameObject.SetActive(false);
            //Destroy(gameObject);
        }
    }
    
}


パンの3Dモデリング

まずLuma AI – Genieというサイトを利用してAIで3Dモデルを生成します。自分の想定通りのモデルが生成されるまで何度も打ち込むテキストを変えて試行錯誤しました。

生成したモデルをlilToonというシェーダーを使用して輪郭線や影設定・リムライトを調整することで、よりゲームの雰囲気に合ったイラスト調の見た目にモデルを近づけました。このようなパンの3Dモデルを20種類以上制作しました。


キャラクター

ゲーム内で登場、登場予定のキャラクターです。左から、エビちゃん、先輩、店長(仮のすがた)です。

その他イラスト

パンの素材や、デバイスデザインのイラストの一部です。パンの素材はなるべくシンプルな見た目になるようにしています。

左はデバイスを格納するステッキの原案です。ここから3Dプリントしやすいように修正を行いました。

テクノフェアでの展示の様子

2024年8月に本学寝屋川キャンパスで開催されたテクノフェアに展示させていただいた時の写真です。


使用・参考にしたもの

Arduino IDE

 追加ライブラリ:MFRC522_I2C、 BluetoothSerial

Unity

 追加アセット:Excel Impoter、 Dotween、 lilToon、

Git Hub (バージョン管理)

作者プロフィール

亀山 瞳

【企画・システム・イラスト担当】

総合情報学部 ゲーム&メディア学科 映像研究室

高田 羽衣

【3Dモデリング・3Dプリント担当】

総合情報学部 ゲーム&メディア学科 映像研究室

コメント


ペンギン2025-02-09T17:30:49

かわいいイラストに独自の世界観で、色んな材料を試すのが楽しかったです!perfectもらえて嬉しかったです!

亀山2025-02-12T00:09:26

遊んでいただき、ありがとうございました!
かわいらしい雰囲気を目指したので、楽しんでもらえてとても嬉しいです。perfectおめでとうございます!!

今川和奏2025-02-08T13:46:02

実際にアイテムを手に取るという体験型ゲームで
特に子どもが興味を持ってくれるような面白いゲームだなと思いました。
また、実際の瓶に入っている素材としてイラストとマッチした素材を使っていることにより没入感が上げるためのこだわりを感じました。

亀山2025-02-09T12:20:34

遊んでいただきありがとうございました!
イラストイメージに合うように材質や色の組み合わせを工夫してみました。細かいこだわりに気付いて下さってとても嬉しいです。