プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

M5Stack Japan Creativity Contest応募作の解説

今年もM5Stack Japan Creativity Contestに応募しました

protopedia.net
protopedia.net
youtu.be

狙い通り、参加賞のTシャツが送られてくる予定です。

今回はゲームを作りました。
プログラミングでゲームを作ってみたいと思っていて、そこにちょうど購入した3軸加速度センサがありました。
小学校の頃に作った迷路を思い出して、これをデジタルで作ってみようと思いました。
(↓こんなやつですが、今時はキットになっているのがあるのですね…)

技術的解説

github.com
プロジェクトはVisual Studio CodeでM5Stackが扱えるPlatform IOを使っています。
Arduino IDEを使うときはsrcフォルダの中身だけを使えば動かせるはずです。
Arduino IDEではM5Stack等ESP32はコンパイルの時間がかかりますが、Platform IOを使ったほうがコンパイルが速くなる傾向があります。

/src/main.cppがメインエントリポイント等を含み、/src/maze_.cppでは迷路を生成します。

迷路は穴掘り法と呼ばれるアルゴリズムを使っています。
これのアルゴリズムでは、スタートを決めると、領域内にランダムにコースを作成します。
このように穴掘り法では最初にすべての領域を壁に初期化し、掘り進めていくことで通路と壁の配列を作成します。
これを配列static int maze[MEIRO_HEIGHT][MEIRO_WIDTH] = {};に保存します。

このアルゴリズムにひと工夫して、スタートからの「道のり」が一番遠くなる場所をゴールに設定するようにしています。

迷路を掘る中ではmazeDepth += 1;のようにスタートからの深さを保持し、戻るときにはmazeDepth -= 1;のように減算し、その場所のスタートからの道のりを算出します。
これが最大値になる場所が最も遠い場所になるので、その場所をゴールに設定します。
最大深さをint mazeDepthMax = 0;に保持し、そのときの座標(その時点での一番遠い場所)をint maxDepthGoal_xy[2];に保持し、最後まで探索が終わると自動的にゴールの座標が求まります。

/src/main.cppではvoid setup()void loop()が主ですが、
void setup()ではi2cの加速度センサの初期化、LCDの初期化を行った後、スタートメニューvoid startMenue()を表示します。
Bボタンが押されると、initRand();createMaze();で迷路を作成します。
カウントダウンcountDown();を行い、ステージを表示しますinitStage();

ゲームがスタートするとvoid loop()に進みます。
ゲーム中は、ボタンの読み取り、画面更新、i2cのデータ受信、ボール(および迷路)の表示、経過時間の表示行います。
ボールがゴール地点に到達したら、void showResult(unsigned long t, bool tooLongTime)へ進みます。
while (true)で入力待ちとなります。

製作の履歴

まずは、加速度センサの動きを試します。


加速度センサの入力に応じてボールが動きます。
この時点で壁との当たり判定は組み込まれていますが、のちにバグがあることが分かります。
また、ボールの速度調整が出来ていません。
壁に引っかかるバグがまだ残っています。
ボールの移動量の分解能がintにキャストされることで荒くなっていたことが原因でした。
引っかかりが無くスムーズに動くようになりました。
タイム計測機能を追加してメインの機能は完成です。
ずべての機能の完成形はYoutubeに。
youtu.be

まとめ

M5Stack Japan Creativity Contest応募作の解説と紹介でした。