Slackで多人数オンラインアクションゲームを作る方法

この記事は[ドワンゴ Advent Calendar](http://qiita.com/advent-calendar/2016/dwango) 8 日目の記事です。
昨日は @mokumoku さんの 「サーバサイド Swift でウェブページを運用している話
」 でした。
実は僕も仕事ではSwiftを書いていて（クライアントサイドですが）、Swiftは好きな言語の一つです。サーバーサイドSwiftはまだ書いたことがないため、記事を読んで挑戦しようと思いました。
今日のお話はSwiftは全く関係ない、SlackとBotとPythonのお話です。

# あるおやすみの日のはなし
ある日、弊社プロダクトの[ニコニコ動画](http://nicovideo.jp)を見ていると[面白い動画](http://www.nicovideo.jp/watch/sm29752761)と出会いました。
面白い実況者が爆弾を使うゲームを自作し、プレイして実況しているのをみて、僕はこう感じました。
「あぁー、僕も爆弾を置いて敵と戦うゲームやりて〜〜」
でも、その時はゲーム機を持っていなくやることができないのが心残りでした。

前置きが長くなりましたが、これは僕が環境に依存しないマルチプラットフォームで動く爆弾を置くゲームを手に入れるまでの物語です。

# Slackというプラットフォーム
[Slackはとても良いプラットフォームだということを以前Slack上で将棋を実装した時](http://kouki.hatenadiary.com/entry/2016/07/19/005006)に書きました。
Slackは非常に優れたプラットフォームで、前回作った将棋のようにゲームを作ることはもちろん、最近流行っているChatOpsに見られるように、メッセージ上に新しいインターフェースとしてのBotを作ることもできます。
他のサービスへのインターフェースとして動くBot、Siriのような人工知能として動くBot、チームメンバーやコミュニティの仲間などが入り混じってコミュニケーションを取ることができるプラットフォームはとても素晴らしいと感じています。その中でもSlackは優れたUIとBotの作りやすさ_(それと少し癖のあるAPI)_ を兼ね備えており、現在何か新しいことをメッセージプラットフォームに載っけたい！と考える人にとっては最適なプロダクトだと考えています。

今回もゲームを実装するプラットフォームとしてSlackを採用しました。

# Slack上でオンラインゲームを作る方法
## グラフィックス
当然ですが、Slackはゲームエンジンではないため、pixelを描画することや任意の画像、ポリゴンをレンダリングすることはできません。
[前回作った将棋](http://kouki.hatenadiary.com/entry/2016/07/19/005006)では、独自の絵文字を登録することにより、複雑な盤面をわかりやすく表示しました。

今回実装したい画面を見てみましょう。この画像は先程の動画のある一場面です。
<img width="639" alt="Screen Shot 2016-12-01 at 1.29.33 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/41033/434c94c2-8307-d2fe-6c65-c6477944e393.png">

一般的な二次元マップになっています。マップチップ1つを絵文字1つで表現することができそうです。また必要なチップは壁、ブロック、爆弾などで、Unicode標準の絵文字だけで全て表現できそうですね。独自絵文字の登録は必要なさそうです。実際に絵文字を並べてMapを作ったものがこちらになります。
<img width="307" alt="Screen Shot 2016-12-01 at 1.38.51 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/41033/22c29a98-c100-7482-6c8e-2e1d69ebdbf3.png">
うん、いい感じですね。
これは、[このようなテキスト](https://gist.github.com/kouki-dan/41ad58a8ad84af88b16a7de9492fd6c1)をSlackに投稿することでレンダリングされます。

また、ゲームの状態が変化すると画面の再描画が必要になります。これはSlackの [chat.update API](https://api.slack.com/methods/chat.update)を使うことで解決できます。Slackでゲームを作るときのバイブルである[Slack as a Game platform](http://niconare.nicovideo.jp/watch/kn1567)にも書かれていますが、APIを呼び出しすぎるとAPI Limitに引っかかってしまうためご注意ください。

## プレイヤーからの入力を受け付ける方法
一般的なプログラムと同じように、ゲームでは入力を受け取り、ゲームロジックに沿った処理をしたあとに出力することを繰り返します。Slack上での出力部分は先程述べましたが、入力はどうすればよいでしょうか。
一般的なゲームであればコントローラーから入力を得たり、PCゲームではキーボードの入力を直接取得できますが、Slack上でそれは実現できません。
これを実現するためにはいくつかの選択肢があります。

1. チャットを使って入力を受ける
1. リアクションを使って入力を受ける
1. Web上などSlackプラットフォーム外に入力を受け付ける機構を用意する

今回のようなリアルタイム性が要求されるゲームでは2のリアクションを使う方法か3のSlackプラットフォーム外で入力を受け付ける方法が適しています。
今回はSlack上ですべてを完結させたいため、2のリアクションを使う方法を採用します。

今回のゲームは、上下左右へ移動、爆弾を置くためのAボタンの5つのボタンがあれば実現できます。
マップに対してBot自身が入力可能なリアクションボタンを置くことにより、ユーザーにリアクションを使うことで入力ができることを示します。
<img width="328" alt="Screen Shot 2016-12-04 at 8.51.17 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/41033/aaabe395-6c56-4fd3-5d56-f18b9eaa4483.png">

Slackの[RTM(Real Time Messaging)API](https://api.slack.com/rtm)を使うことにより、リアクションの[追加](https://api.slack.com/events/reaction_added)と[削除](https://api.slack.com/events/reaction_removed)のメッセージを受け取ることができます。これはどちらもボタンが押されたことを意味します。このどちらかのメッセージを受け取ったときに、リアクションを追加（または削除）したユーザーの入力とし、ゲームロジックに反映させることで操作しやすいUIをSlack上に提供できます。

# 実装してみた
さて、ここまででSlack上にオンラインアクションゲームを作る方法を出力と入力に分けて見てきました。
ここで紹介してきた方法を使って実際に実装したゲームがこちらになります。
https://github.com/setokinto/slack-bomber

実際に使ってみたい方はDockerを使うことで簡単に試すことができます。
DockerがインストールされたPCで
`docker run --env API_TOKEN="<Your Slack Bot Token>" setokinto/slack-bomber`
API_TOKENのところを実際にSlackから取得したBot Tokenに置き換えた上で実行してください。
そのボットがいるチャンネルで
`@bot-name start with @username` (usernameには一緒に参加させたいユーザー名）
とすることで開始します。
<img width="389" alt="Screen Shot 2016-12-05 at 12.21.32 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/41033/7cb0650f-d1fd-003f-75e1-061fa852431c.png">
ぜひいろんなSlackチームで動かしてほしいです。

ゲームを進めて行くとこのような感じになっていきます
<img width="327" alt="Screen Shot 2016-12-05 at 12.34.55 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/41033/315e4eeb-2b13-f304-c8dd-c25c3bfae050.png">

# 実装にあたって
Slackでオンラインゲームを作ると、ネットワーク部分はすべてSlackが肩代わりしてくれるので、自分で実装することはゲームロジックだけに集中できるためとても楽に開発できます。作り方はほぼ一般的なゲームと同じなのですが、描画性能が著しく低いことだけは気をつけなくてはいけません。
一般的なゲームでは1秒間に30回や60回も画面を更新することが普通ですが、Slackで作るとそれは実現できません。今回は0.6秒または0.7秒に1度くらいに1度画面を更新しています。グラフィックスの項で書いたように、API Limitがあるからです。そこの部分だけは気をつけてコーディング、設計していく必要があります。

また、fpsが低いせいで操作ミスが多発してしまい、POOR MANと同じように1度爆発すればゲーム終了にしてしまうと戦いが始まる前に終わってしまうので、ライフ制を導入しました。

この記事を見て、Slack上にオンラインゲームを作りたいと思った方も、Slackの特徴を考えSlackならではの使いやすい特徴を考えて行くと良いでしょう。

# まとめ
Slackは素晴らしいプラットフォームでチャットもできるしゲームもできます。それにAPIが広く公開されているために発展も考えられ、メッセージと言う誰もが使うソフトウェアに色々な機能やサービスがインテグレートされていくこれからには非常に未来を感じます。
他のメッセージサービスでもAPIを公開しているものが多くなってきています。Bot Platformは2017年も熱いものになると思われるので、皆さんいろんなものを作ってみましょう。
色々なサービスの中でもSlackは特にエンジニアに対して機能が開放されていて、APIも充実しています。APIは少し癖がありますが、機能は十分なので、まずはSlackをプラットフォームとして自分の思う何かを作ってみてはいかがでしょうか。