この記事は Slack Advent Calendar 2016 24日目の記事です。
半年ほど前に下のようなエントリを書きました。
Slack上でインタラクティブに倉庫番を遊べるhubot-slack-soukobanを作った - MANA-DOT
Slackのリアクション機能と編集機能を活用し、Slack上でインタラクティブにゲームを作るという趣旨の内容でした。 今回は、このようなゲームを汎用的に作るための slack-game-bot というnpmパッケージを (アドベントカレンダーのネタのために)作ったので紹介します。
概要
兎にも角にも、例を見ていただくのが早いです。
const {Game, GameBot} = require('slack-game-bot'); class MyGame extends Game { getButtons() { return ['one', 'two', 'three']; } async initialize() { await this.draw('press button!'); } async onPushButton(reactionType) { await this.draw(reactionType); } } new GameBot({ myGame: MyGame, }).run(process.env.SLACK_TOKEN);
上記のコードを(babelなど然るべき変換をしたのちに)実行すると、指定したトークンに紐づくSlackチームでbotが動き、以下のような挙動をします。
このフレームワークは、自分でゲームを作るための抽象クラス Game
と、 作ったGameをbot上で動かすための GameBot
クラスから成ります。
Gameクラス
Game
クラスには抽象メソッド getButtons
, initialize
, onPushButton
があり、それぞれを実装することでゲームを作ります。
getButtons
はゲームで利用するボタンの配列を返すようにします。例では、 ['one', 'two', 'three']
を指定しているため、 :one:
, :two:
,
:three:
の3つのボタンが(リアクションとして)描画されています。
initialize
では初期化処理を記述し、最初の描画を draw
メソッドを用いて行います。また、ここで this
に対してゲームの初期状態をセットしておく
こともできます。
onPushButton
はユーザーがボタンを押したときに発火し、押されたリアクションの種別と、押したユーザーの情報が得られます。
ここで、押されたボタンの内容に従って状態を書き換えた後に draw
してあげることでインタラクティブなゲームを作ることができます。
GameBotクラス
GameBot
クラスに実装した Game
を登録し、トークンを指定して run
メソッドを実行することでbotが起動します。
botは、登録の際に指定したオブジェクトのキーと同一の文字列に反応し、そのゲームを開始します。
複数回反応した場合は別々に新規ゲームが開始されます。また、複数の Game
を別々のキーに登録することも可能です。
例
src/samples 下に配置してあります。
Janken
乱数を使ったシンプルなじゃんけんゲームです。ユーザー名を利用するサンプルでもあります。
Slot
setTimeoutを使い、定期的に表示を書き換えることで実装したスロットゲームです。
Soukoban
以前実装した倉庫番 を移植したものです。ゲーム起動時に引数を受け付けるサンプルにもなっています。
Maze
自動生成された迷路をさまようだけのクソゲーです。
余談
Slackには messages buttons という、よりゲーム向け(に悪用できそうな)機能もあり、 当初こちらでボタンを実装しようと思ったのですが、ボタンのhookを受けるためのサーバーが必要なようであったため、手軽さにかけると思い 今回は見送りました。
もっと気軽に使えるようにならないかなあ。
あとがき
奇しくも今日はクリスマス・イブとなります。みなさんクリスマスプレゼントは決まりましたか? まだの方はSlack上で遊べるゲームをプレゼントしてみてはいかがでしょうか? 職場の生産性を低下させること間違いなしです。
Slack上でゲームを作ることのメリットですが、チャットに参加している全員が参加可能なゲームを作れるというのが大きいです。 たかが倉庫番でも、複数人が操作するとまた違った面白さが見えてきます。 Twitchポケモンのようなカオスなゲームを作れる可能性を秘めています。
※この記事の内容は突貫で作ったネタですので、フレームワークのくせに設計が美しくないだとか、テストがないだとかは勘弁してください><。