読者です 読者をやめる 読者になる 読者になる

アーキテクチャをスマートに。

株式会社ネオジニア代表。ITアーキテクトとしてのお仕事や考えていることなどをたまに綴っています。(記事の内容は個人の見解に基づくものであり、所属組織を代表するものではありません)

ネオ富豪の開催にあたって(2)アーキテクチャが決まるまで

.NET 考え方 プログラミング

当初の構想

ナポレオンアプリを作った経験から、画面の構成はほとんど迷うことなく決まっていました。(なので自然と5人対戦という仕様になりました)
ゲームシステムも、マスタープログラムが1つあって、そこにプレイヤープログラムがいくつもつながって連携しながら動く、という考え方はそのまま採用しました。
でネポレオンで実現できていなかったネット対戦の構想を思い出しました。
マスターとプレイヤーをクラサバ方式にして、TCP/IP でセッション張ってプロトコル定義して通信するようにしてみよう、というアイデアです。
それが実現できれば、プレイヤープログラムの開発に於いて制約がほとんどなくなり、どんなプログラミング言語で実装してもいいし、どんなプラットフォームで実行してもいいということになります。自由度が飛躍的にあがって、よりチャレンジングな企画になると思ったからです。
もし万が一にもネット対戦が実現できなかった場合は、Java でプレイヤープログラムの interface を書いておいて、参加者にはそれを implement したクラスを作って来てもらい、大会当日にクラスファイルをロードして呼び出すというやり方にしようと考えていました。

あと、ネット対戦できる仕組みにさらに面白みを追加するために、観戦できる仕組みも付けたいと考えました。
プレイヤーとは別に、観戦者という第三者がマスタサーバに接続し、全員の手札が見れる状態でゲーム画面を眺めることができるようなイメージです。

通信プロトコル

学生時代にXプロトコルの解析を少しやったのと、C言語でのネットワークプログラミングの経験が多かったので、
なるべく簡単に、テキストベースで、取り扱いやすいものにしよう、という基準がありました。
そこで最初に考えたのは、

C;RGST;id=ID
S;DEEL;deck=手札
S;STRT;order=順番
...

みたいな感じでした。
先頭位置文字が発信元を表し(クライアント or サーバ)、次の4文字でメッセージ種別、その後ろにメッセージ本文、それらをセミコロンで区切る、みたいなイメージです。

でも構成が固まっていくうちに、このプロトコルはやめました。

クライアントを JavaScript で実装することを検討したときに、WebSocket が使えそうだとわかり、JSON形式で構造体をまるごとやりとりする方式にした方が楽ちんだと思ったからです。
そしてもうひとつ重要なポイントとして、ステートレスな点があげられます。
ステートレスとは、状態遷移がないということです。
逆に状態遷移をもつプロトコルはステートフルといい、通信が進むにつれて内部の状態を更新しながら動くような、対話形式のプロトコルになります。
対してステートレスプロトコルは、通信ごとに入出力データが完結しており、プログラムの内部状態を更新する必要がありません。
TCPでセッションを張っているのだから、ステートフルなプロトコルを想像しがちだったんですが、通信量の削減や効率化を求めるよりも、参加者にとって面倒な通信制御は出来るだけ少なく、複雑な制御を要しない方式がよいだろうという設計思想から、ステートレスプロトコルにしました。
これにより、万が一プレイ中にクライアントとの接続が切れても、再接続することによって簡単にゲームに復帰してプレイ継続できるような仕組みが副次的に実現できました。

WebSocketの採用

最初は、SOAP+WSDL規格での通信を検討しました。あとWCFも有力候補にあがっていました。ところがどれもWeb標準技術として浸透しているとは言い難く、技術革新の早いIT業界では少し先進性に欠け、今後の応用の可能性も低いように感じました。
そういう意味で WebSocket はより新しい技術であり、Web上で普及できそうなパワーを秘めていることから技術習得によって得られるアドバンテージは大きいんじゃないかと判断しました。
WebSocketは様々なプラットフォームでフリーなライブラリが出揃っていることがわかり*1、従来方式の TCP/IP ネットワークプログラミングよりも手軽に作れるんじゃないかという事で採用に至りました。
同様に、通信プロトコルJSON形式にしました。これも、XMLと並んで事実上のWeb標準フォーマットになりつつあり、JavaScript以外にも様々なプラットフォームでライブラリが出揃っていて、構造化データの取り扱いが楽にできると判断したからです。
プロトコル定義も、それを前提に構成しなおしました。

サーバ側のアーキテクチャ

サーバ側は、前から気になっていた C++ 向けのWebフレームワーク TreeFrog を試してみるか、初めての Scara で LiftPlay にチャレンジしてみるか、お気に入りの C# で修行中の ASP.NET MVC 4 でいくか悩みました。
まず、それらのフレームワークで WebSocket が簡単に使えるかどうか調査しました。それが11月13日の記事でした。

サーバのホスティングについては、Linux + Mono も捨てがたい構成だったのですが、会社の BizSpark ライセンスを活用して Windows Azure を試してみたかったので、そっちにしました。
クラウド上に仮想マシンを作らなくとも、"Webサイト"というホスティング形態でオプション設定を変更すれば WebSocket が使えることがわかり、結果的に今回の構成にピッタリで、他のフレームワークを習得する時間的コストもバカにならないので、もうこの構成案で固まりました。
ここまでは11月25日ぐらいには決まっていました。

プレイ画面

Web上でプレイ出来るようにしたかったので、JavaScript で実装するつもりでした。
Flash はさすがに選択肢になかったですね。。。Unity も試してみたかったけど、特別なアプリをインストールせずに利用できたほうがいいと考えました。
で、そういえばほぼ毎月購読している技術誌 SoftwareDesign に enchant.js ってのが載ってたなと思って、軽く触ってみることに。また、調査していくうちに tmlib っていうのもあることを知って、最初そっちを試してたんですが、どうにもうまくいかず、enchant.js の方がすんなり動かせました。*2
とにかく時間がないので、ライブラリの内部構造まで理解する余裕はないと思っていたので、enchant をブラックボックスとしてゲーム画面の作りこみを始めました。
ところが実際に作り始めると、なかなか思うような制御が出来ず、色々はまりどころがありました。結局、ブラックボックスとしていた enchant が内部で何をしているのかを調べることに着手し、それが少し理解できてくると、今まで上手く制御出来なかったことがするすると出来るようになりました。
やはり内部の動きを理解してやる方が早いですね。

enchant.js についての感想ですが、本格的なゲームプログラミングをしたわけじゃないので、的確な考察が出来ているとは言いがたいのですが、触ってて面白かったです。ゲームエンジンという事もあり、素直に楽しくプログラミングできました。普段は業務系のシステムばかり作ってるので、いい経験になりました。
まだ出来て間もない新しいライブラリのようで、バグがあったり、IEで動かない箇所があったりするのは仕方ないと割り切っています。それでも、ネット上に情報が多いので調べるときに楽でした。ただ、使い方にちょっとクセがあるように感じました。

大会ルールの設定

まず第一に、大会のルールを決めないことには開催できないので、早いうちに決めきってしまおうと思いました。
なるべくシンプルに簡単にしておいて、多忙なエンジニアでも手早く実装できるようにして参加のハードルを下げたいと思っていました。しかしながら、簡単にしすぎるのも困ったことがあって、ほとんど初期手札の運によって勝敗が決まってしまう、ということです。
なので出来れば少しの追加ルールを採用して、運ではなく戦術によって勝敗が決まるようにしたいと考えました。
このバランスがすごく難しく、結果的に1つに決めきれず、簡易的なルール(クラスA)と戦術が求められるルール(クラスB)として2種類のルールを用意するに至りました。

*1:http://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations

*2:いま改めてググってみたら、すごいポップな感じの公式ページが出来てますね。こんなんなかったで。。。orz http://phi-jp.github.io/tmlib.js/