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は心の癒やしになるでしょう…

大洗のあんこう祭りに行ってきた

11月16日に行われた大洗あんこう祭りに行ってきました。大洗というとガールズアンドパンツァーというアニメ作品で一躍有名になった場所です。僕もガルパン経由で知りました。

その大洗で毎年11月に行われているのがあんこう祭りで、ここ数年はガルパンとのコラボが毎年行われているようです。今回その祭りの様子を写真に撮ってきました。

続きを読む

Intellij IDEAのscope language

ElmのコンパイルをFileWatcherプラグインを使ってやろうとしたら、ちょっとだけ躓いたのでメモ。

FileWatcherプラグインでElmのファイルを指定する場合、*.elmとかだと指定できない。なぜならScope Languageというのを使わないといけないから。

elmだと、 file:*/(elmがあるディレクトリ)/*.elm みたいな感じで行ける。

ElmでWebSocket接続の例

説明

WebSocketというのは、TCPで使える(主にブラウザー用の)プロトコルです。

WebSocket(ウェブソケット)は、コンピュータ・ネットワーク用の通信規格の1つである。インターネットの標準化団体であるW3CIETFがウェブサーバーとウェブブラウザとの間の通信のために規定を予定している双方向通信用の技術規格であり、APIW3Cが、WebSocket プロトコルIETFが策定に関与している。プロトコルの仕様は RFC 6455。TCP上で動く。

引用元 Wikipedia

Javascriptから簡単に利用することができ、Httpに比べ低いレイテンシーでリアルタイムな通信に向いていると言われています。

WebSocketプロトコルについては次の2つのウェブサイトが参考になりました。

RFC6455 — The WebSocket Protocol 日本語訳

  • RFC6455の日本語訳を公開してくださってる方がいらっしゃいました。有り難いですね!しかもちゃんと最新版にアップデートされてます。

Block Rockin' Codes - WebSocket サーバの実装とプロトコル解説

  • サーバー側でWebSocketの通信を行う部分を書いて見たのですが、その時一番参考にしたウェブサイトです。

WebSocket関連の記事・ソースコードは、以前の版(ドラフト版)をベースに書かれたものが多くあります。最新版とドラフト版ではかなり仕様が変わっているので、注意したほうが良いです。

ElmにもWebSocketを使うためのライブラリが備わっていて~ / Catalog / Elm / WebSocket、非常にシンプルなconnectという関数のみが用意されています。

connect : String -> Signal String -> Signal String

という型からわかるように、WebSocketへの送信も受信もどちらもシグナルになります。Httpと同じですね。正直エラーとかクローズとかどうやってハンドリングするのかわかりませんが、まずは使えることを喜びましょう。

今回ws://echo.websocket.orgにテキストを投げてそれを表示するだけのスクリプトを書きました。ご参考まで。

WebSocketはブラウザでTCPのようなコネクション持続型の通信を行える、非常に興味深い技術だと感じました。仕様もほぼ固まっている?ようなので、色々と使えたら面白いですね。現状WebSocketの中身をブラウザのデバッグツールでみれるのは、Chromeだけのようです。

続きを読む

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