SF(すごくふつう)なブログ

記録・メモ・自己啓発・他

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への入力、返り値をそれぞれ独立したシグナルにしました。

WebSocketシグナル部分

これでfoldpで作るシグナルにWebSocketの返り値シグナルを入れても、WebSocketへ自由に入力させることができます。

出力シグナル

Elmからサーバーサイドへは、WebSocketへの入力を行うことで出力を行います。

出力シグナル部分

ゲーム関数

ゲーム関数は、クライアント側の中心となる存在です。この中で、

  • WebSocketから受け取った返り値の処理
  • 各種計算
  • ゲーム状態の遷移

これらの処理を全て行います。

ゲーム関数部分

この中の処理はもう普通の処理です。foldpとかElm特有の処理は出てきません。

まとめ

やっぱりリアクティブを意識するのが重要な感じがします。このゲームでは

  • FPSとなるシグナル
  • サーバー側からのシグナル

という2つの方向性が違うシグナルが有り、現状ではFPSの方で強制的にサーバー側のシグナルを同期させています。ただそのせいでサーバー側からのシグナルを一部取りこぼす(他のユーザーが生成したブロックの情報が同期されなかったり)ことがあるので、なんともどうしたものか…と思っています。

解決策としては、

  • サーバー側でクライアントが必ず受け取ったことが確認できない限りメッセージをキャッシュする
  • サーバー側とクライアント側のメッセージ送受信間隔を同期させる

ぐらいしか思いつきませぬ。

Elmのメリット

最後に、Elmのメリットをいくつか。

モジュールの分割が楽

モジュールを分割するのが楽です。しかもひとつのjavascriptファイルに簡単にコンパイルできるので、保守性が抜群です。

綺麗に書ける

javascriptのグチャッとしたソースコードに精神を削られている人も多いと思います。きっとElmは心の癒やしになるでしょう…

当ブログのコンテンツの引用は自由です。