M5Stack で「あみだくじ対戦ゲーム」を作った話

* 社内の有志で定期的に行っているハッカソンで  
「あみだくじ対戦ゲーム」を作りました。
	* コードは [GitHub](https://github.com/andromedroid/ame/blob/master/m5stack/amida.py) にありますので、  
	よろしければ遊んでみてください。

## Prologue

* 後輩の某氏が  
**「ねんがんの M5Stack を てにいれたぞー」**  
というので、死蔵しているウチの M5Stack Fire があるし、  
一緒に対戦ゲームを作ろうということで、開催の運びとなりました。

## 仕様 draft 投稿

* Slack に投稿した当時の内容がこちらです

~~~
準備と実装：
1. N 台の m5stack を用意する
2. 何らかの方法で相互無線通信できるようにする
3. 何らかの方法であみだくじと弾丸を描画できるようにする

遊び方：
1. 弾丸を撃つ側と撃たれる側に分かれる
2. 撃つ側は３つのボタンの好きなボタンを押す
3. 押されたボタンが撃たれる側に届く（無線通信）
4. 撃たれる側はあみだくじと弾丸の描画を開始
　あみだくじを辿り終わるまでに正解のボタンを押せたらガード成功。
  攻守チェンジ。
5. 以下同文

ポイント：
* 後輩ンゴは「Arduino 開発環境」で、@andromedroid は
  「MicroPython 開発環境」で上記の仕様を満たす実装を行う。
* 難易度設定はそれぞれの開発者に委ねられるが、ゲームとして
  面白いレベルを目指す（あみだの複雑さ、弾丸の到達速度など）。

以上
~~~

* 最終仕様としては、M5Stack は全て「撃たれる方」となり、
「撃つ方」は MQTT Broker たる Raspberry Pi0 が担うことになりました。

* channel への投稿なので、我々はこれをやりますと
全員を前に宣言した形です。

しかし、新人さんも来るハッカソンで
「がんばったけど開発が終わりませんでした」
というブサマな姿を晒すわけにはいかないという強烈な**虚栄心**が働き、
**フライングで**作業を開始することになります。

## フライング作業 〜 最初のプロトタイプ

* まず、開発環境には [**UIFlow**](https://m5stack.github.io/UIFlow_doc/ja/) を選びました。
	* 途中でバージョンが上がったりして、最終的には  
	**v1.3.2** 上で動くコードになりました。

* 普段はゲーム屋でも GUI 屋でもないので、
アニメーションとかどうしたら良いかもよく分からず、
UIFlow にある demo examples から参考になるものを探し、
バッテリーアニメーションの demo をベースにスタートしました。

* 最初の AMIDA (2019/05/23)

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">2019/05/23 時点の AMIDA <a href="https://t.co/RPI6YyE7BX">pic.twitter.com/RPI6YyE7BX</a></p>&mdash; AndromeDroid (@AndromeDroid) <a href="https://twitter.com/AndromeDroid/status/1144992624715034624?ref_src=twsrc%5Etfw">2019年6月29日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

* 雰囲気は伝わるでしょうか。  
これを作って、ちょっとできそうな気がしてきました。

## 通信処理 (MQTT) の動作確認

* 初めは BLE で P2P 通信をしようと考えたのですが、
UIFlow で BLE を扱うライブラリは無さそうでした。

* そこで、お互いの環境で利用可能な MQTT を使うことにして、
Pi0 + mosquitto で Broker を立て、そこから publish される
**"missile"** topic を subscribe する形にしました。

* 通信のモジュールは開発でも苦しむことが多いので、
hello_mqtt.py で簡単に仕様把握と動作確認をしたところ、
思いの外あっけなく動きました。

* pi0 + mosquitto broker
	* こちらの記事を参考にしました。  
	[Raspberry Pi で mosquitto を使う](https://qiita.com/ekzemplaro/items/ab90dd630c3ad8e819ab)

* M5Stack の hello_mqtt.py

~~~python
from m5stack import *
from m5ui import *
from uiflow import *
from m5mqtt import M5mqtt

setScreenColor( 0x222222)

m5mqtt = M5mqtt( '', '192.168.0.255', 1883, '', '', 300)

def fun_light_( topic_data) :
  # global params
  rgb.setColorAll( 0xff0000)
# pass

m5mqtt.subscribe( str( 'light'), fun_light_)

def btnA_wasPressed():
  # global params
  m5mqtt.publish( str( 'light'),str( 'A'))
# pass

btnA.wasPressed( btnA_wasPressed)

m5mqtt.start()
~~~

* 唯一面倒なのが、UIFlow で MQTT 機能を利用する場合には  
オンライン実行ができず、ダウンロードでの実行しかできない点で、  
いちいち更新のためにアプリを切り替える必要があります。

## Amida クラスの作成

* その後、後輩の某氏が立派な AMIDA trace アニメーションと
防御正否判定の実装まで終えるフライングをかましてきたために、
またまた焦燥感に追われることになりました。

* とりま追いつくしか無いので、この時点でゲームの
進行を管理する、以下のようなクラスを作ることにしました。
	1. "missile" topic を受信したら instance 生成
	1. random で AMIDA の horizontal line を **10 行分**生成
		* 0: なし
		* 1: 左側
		* 2: 右側
	1. missile が AMIDA trace を開始
		* 先の random 生成結果に従い line trace する
	1. shield の button を callback で受け取る
	1. missile が着弾、防御正否判定し effect

* 実行動画 (2019/06/12)

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">2019/06/12 時点の AMIDA <a href="https://t.co/Bswvig5VL5">pic.twitter.com/Bswvig5VL5</a></p>&mdash; AndromeDroid (@AndromeDroid) <a href="https://twitter.com/AndromeDroid/status/1144992793242132480?ref_src=twsrc%5Etfw">2019年6月29日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

* アニメーションのお作法が良くないのか、  
Circle の描画が崩れてパック○ンみたいになります。
	* **まあええか！**
	* 通った後に道も無くなるけど、**パッ○マンらしくてええわ！**

## 当日

* いざ、尋常に！
	* Oculus Quest を体験させてもらったりして**穏やかに時間が経過**
	* 後輩の某氏に**「MQTT の動作を確認したいのですが」**と言われ、  
慌てて Pi0 のセットアップを行う。
	* 当日のトラブルあるあるで、Wi-Fi ルーターの**キャパオーバー**  
と思われる DHCP の IP 割り当てが来なかったりが発生。

* そんな感じで、とりあえずリリースしました。
	* [**完成版コード**](https://github.com/andromedroid/ame/blob/master/m5stack/amida.py)

	* 当日は MQTT Broker から定期的に飛来する missile を  
subscribe して遊ぶようにしていましたが、  
こちらのコードでは、単品で遊べるように main() 内で  
定期的に missile を飛ばすようにしました。

	* 時々 AMIDA の**道を踏み外すバグ**があったりして、  
なかなか楽しく遊んでもらうことができました。

本日は以上です :smiley: