ElmでWebsocketを使ってゲームを作ってみた例
説明
ElmでWebsocketを使って、非常にシンプルなネットゲームを作ってみました。
実際に動いているのはこちら ※サーバー側(Erlang)がうまくバックグラウンドで動かせていないせいで、たまーにしかプレイできません。すんません。僕のErlang力不足が原因です…
構成
サーバー側はErlangだけ、クライアント側はElm+Javascript(Websocketのコネクション周り)で作っています。
クライアント側
Elmで作っています。Elmです。Elmですね。
Elmはリアクティブプログラミングというプログラミングパラダイムの上に存在します。なので、常にリアクティブな思考を持って作る必要があります。
ベースとなるシグナルを考える
僕の中でリアクティブプログラミングは、電気回路のイメージがあります。予め作られた回路(Elmで書かれた関数)に、信号(Signal)を流し込み、駆動する。そういう感じです。
入力シグナル
入力シグナルの中に、ユーザーの入力を全て詰め込みました。というのも、foldpでゲームエントリー関数を畳み込んでしまうと、もうそこに別のユーザー入力(つまりシグナル)を入れるのがかなり難しそうだと感じたからです。
このシグナルを、foldpで初期ゲーム状態を与えた状態で畳み込みます。
他にもウェブソケットのシグナルを扱わないといけないのですが、やっかいなことにElmのWebSocketを開く関数は
String -> Signal String -> Signal String
という型を持っていて、予め作ったシグナルを渡さないと返り値のシグナルが貰えないようになっています。つまり、シグナルのループが出来ないんです。ちょっと良い説明が出来ないのですが、foldpでWebSocketの返り値を含むような閉じたシグナルを作ると、そこからWebSocketの入力に何かを突っ込むことが非常に難しい感じになります。
じゃあどうしたの?
WebSocketはJavascript側でハンドルし、Portという仕組みを使ってWebSocketへの入力、返り値をそれぞれ独立したシグナルにしました。
これでfoldpで作るシグナルにWebSocketの返り値シグナルを入れても、WebSocketへ自由に入力させることができます。
出力シグナル
Elmからサーバーサイドへは、WebSocketへの入力を行うことで出力を行います。
ゲーム関数
ゲーム関数は、クライアント側の中心となる存在です。この中で、
- WebSocketから受け取った返り値の処理
- 各種計算
- ゲーム状態の遷移
これらの処理を全て行います。
この中の処理はもう普通の処理です。foldpとかElm特有の処理は出てきません。
まとめ
やっぱりリアクティブを意識するのが重要な感じがします。このゲームでは
- FPSとなるシグナル
- サーバー側からのシグナル
という2つの方向性が違うシグナルが有り、現状ではFPSの方で強制的にサーバー側のシグナルを同期させています。ただそのせいでサーバー側からのシグナルを一部取りこぼす(他のユーザーが生成したブロックの情報が同期されなかったり)ことがあるので、なんともどうしたものか…と思っています。
解決策としては、
- サーバー側でクライアントが必ず受け取ったことが確認できない限りメッセージをキャッシュする
- サーバー側とクライアント側のメッセージ送受信間隔を同期させる
ぐらいしか思いつきませぬ。
Elmのメリット
最後に、Elmのメリットをいくつか。
モジュールの分割が楽
モジュールを分割するのが楽です。しかもひとつのjavascriptファイルに簡単にコンパイルできるので、保守性が抜群です。
綺麗に書ける
javascriptのグチャッとしたソースコードに精神を削られている人も多いと思います。きっとElmは心の癒やしになるでしょう…
大洗のあんこう祭りに行ってきた
11月16日に行われた大洗あんこう祭りに行ってきました。大洗というとガールズアンドパンツァーというアニメ作品で一躍有名になった場所です。僕もガルパン経由で知りました。
その大洗で毎年11月に行われているのがあんこう祭りで、ここ数年はガルパンとのコラボが毎年行われているようです。今回その祭りの様子を写真に撮ってきました。
続きを読むIntellij IDEAでタブのカラーとかを変更
IDEAを使っていると、テーマを変えた時にファイルのタブの色が真っ黒になって非常に見難くなることがある。
そういうときに画像に示すオプションを外すとファイルタブの色やファイルリストの色が消えて見やすくなる。
Intellij IDEAのscope language
ElmのコンパイルをFileWatcherプラグインを使ってやろうとしたら、ちょっとだけ躓いたのでメモ。
FileWatcherプラグインでElmのファイルを指定する場合、*.elm
とかだと指定できない。なぜならScope Languageというのを使わないといけないから。
elmだと、
file:*/(elmがあるディレクトリ)/*.elm
みたいな感じで行ける。