西田慎吾

WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て!(後編)

WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て!(後編)

前回に引き続きHTML5 Japan Cup 2014にてWebGL賞優秀賞をいただいたオンラインレースゲーム、JS-Racingの技術解説をさせていただきます。

img14

サーバサイドの使用技術

サーバサイドの技術としてNode.jsを使用しています。Node.jsはサーバーサイドで動作するJavaScriptで、ノンブロッキングI/Oというモデルを採用しています。非同期処理でデータベースへのアクセスとWebページの表示を別々に行ってくれるので、ストレスなく大量のページの表示が出来ます。また、Socket.ioというライブラリを扱うことで、WebSocketを使用したリアルタイム通信を実現するができます。

Node.jsでWebアプリケーションを構築する場合、実験的にローカルのみの開発の場合は問題ありませんが、公開するとなると、Node.jsをインストールして実行できるサーバが必要になります。そのためには共有サーバのレンタルではなく、管理者権限 (root) が付与される専用サーバや、仮想専用サーバ(VPS)のレンタルが必要になると思います。管理者権限のため自由に環境をセットアップする事ができるために、そのWebアプリケーションに合わせた環境構築が可能になります。

ExpressによるWebアプリケーションフレームワークの利用

Node.jsで作成したWebアプリケーションの場合、リクエストURIの解析からファイルの配信など、HTTPサーバの機能を実装しなくてはいけません。これらの基本機能が備わったWebアプリケーションフレームワークを利用することで、非常に手軽にWebアプリケーションを作成できます。今回は、多数開発されているWebフレームワークのなかでも、有名で多く利用されているExpressを利用しました。

22行目のreq.query.idhttp://js-racing.knockknock.jp:3000/controller.html?id=000000として渡された、URLパラメータのidの値が参照できます。この値は、ソケット通信時に発行されたソケットIDの値で、PCから発行されたスマフォ用のURL(QRコードか短縮URL)にURLパラメータとして付加されたもので、この値を元にPCとスマートフォンとのペアリングを行います。

ExpressはHTMLのテンプレートエンジンとしてJadeか、ejsを選択することができます。Jadeはインデントが必須です。閉じタグを省略できる代わりに、DOMの入れ子構造に沿って適切にインデントを使用する必要があります。基本的な記法がHTMLとは違うために、HTMLに親しんだマークアップエンジニアからすれば、慣れるまで違和感があるものだと思います。ejsはJadeとは違い、基本的な記法はHTMLをベースにしていますので、ローカルでくみ上げたHTMLをejsに組み込むことが容易です。今回はより楽にコード量を少なくHTMLを構築したいという点で、閉じたタグなしで記述できるJadeを選択しています。

Jadeはこのようにインデントによって、要素の入れ子構造を定義しています。そのため閉じタグが不要で、HTMLを非常に簡略化して記述することが可能になります。HTMLを簡略化できるだけがJadeの特徴ではありません。HTMLをコンポーネント化して再利用したり、条件分岐をさせたり、繰り返し処理をさせたり、これまでサーバサイドで行っていたようなことがNode.jsで可能になります。ちなみにCSSはSass(Compass)を使い、記法にはBEMという命名規則を採用しています。

Socket.ioによるリアルタイム通信

車の同時走行と、スマートフォンからの車の操作を実現するためには、ブラウザとサーバ双方から、任意のタイミングでデータを送受信する必要があります。このリアルタイム通信を実現するために、Socket.ioを利用しています。Socket.ioはWebSocketなどのリアルタイム通信技術をラップして、シンプルなAPIを提供しているため、通信部分の煩雑さを意識することなく、リアルタイム通信を簡単に構築することができます。

スマートフォンからの車の操作を実現するために、接続時に発行されたソケットIDを共有することで、スマートフォンとPCをペアリングして相互通信しています。サーバを介しての通信なので、若干のタイムラグが発生する懸念もあったのですが、現状ではタイムラグを感じることはありませんでした。環境に依存することですので、あくまで今回の場合はということですが。

接続している全てのクライアントに、接続している全てのクライアントの情報を送信するイベントは、ネットワークの負荷を考えて、1秒間に3回と制限をかけています。つまり3FPSのタイミングで同期をとることになりますが、クライアント側では30FPSでゲームが進行しているために、タイムラグが発生してしまいます。タイムラグによって発生する違和感をなくすために、クライアント側ではサーバ側から配信されるクライアント情報を元に、前回配信された情報との差分を10で割った値を算出して、クライアント側の1FPS毎の値として反映させ、違和感を解消しています。

MongoDBでラップタイムの保存と走行データの保存

ラップタイムを保存したり、走行データを保存するのにデータベースとしてMongoDBを利用しています。MongoDBは、オープンソースのドキュメント指向データベースです。RDBMSのようにレコードをテーブルに格納するのではなく、ドキュメントと呼ばれる構造的データをオブジェクト形式でデータを管理します。 ちなみにNode.jsからMongooseを利用し、MongoDBに接続しています。Mongooseでは、Schemaインスタンスを通してModelを定義する事ができます。以下のようなオブジェクト形式でデータを管理出来るのが、MongoDBの特徴です。

走行データは1秒間に30回、車の位置と角度を記録した配列ですので、全てのユーザーの分だけ保存すると、データ量が肥大してしまう可能性があります。データ量を押さえるために、ラップタイムでソートして10位圏外の走行データは保持していません。

サーバサイドではNode.jsのおかげで、Webアプリケーションを構築する環境がとても整ってきていると思います。 基本的な言語はJavaScriptですので、サーバサイドもフロントエンドエンジニアが押さえるべき領域になっているのではと思います。

その他の技術的トピック

サーバサイド、クライアントサイドの技術それぞれの紹介を軸として、説明させていただきましたが、これ以外にもいくつか工夫した、技術的なポイントがありますので、紹介します。

コースデータの共有

3D表現を利用するために使用したthree.jsと、ゲームエンジンとして使った2D物理エンジンBox2DJSで、コースデータを共有するために2次元配列を使用しました。各値には数値を格納して、数値によってthree.jsでは壁、道路、芝、タイヤ、木、等の3Dモデルが配置され、Box2DJSでは3Dモデルの形状に沿った障害物を配置します。ちなみに開発当初、コースエディット機能や、SNSでコース共有機能等を考えていましたので、テキストデータとして扱いやすい2次元配列をコースデータとして採用したという経緯があります。

ただ、このような膨大な量の2次元配列を、テキストエディタで作成、編集するのは非常に非効率だと考えて、途中からExcelによって管理する方法に切り替えました。Excelでは条件付き書式を設定して、セルの値によって、わかりやすいように色づけするように設定しています。データ書き出しの際には、ExcelからCSVデータとしてテキストデータを書き出して、CSVデータをテキストエディタで置換して2次元配列にしています。

img12

コースの装飾

コースは直線と直角だけではなく、カーブ等の曲線も再現できなくてはいけません。2次元配列をコースデータとして利用する場合は、この点を補完する必要があります。また、コースというのは大抵、両脇のシケインとの境目にラインが引いてあります。こういったアスファルトや芝生といった要素以外の装飾を、周りの要素の配置条件に応じて追加することで、よりコースらしい外観を作る事ができます。下のキャプチャが装飾やカーブの補完をかけている物と、コースデータをそのまま表示したものとの違いです。

img13

まとめ

以上が今回作成したJS-Racingの主な技術解説になります。Webアプリケーションを構築するには、今回解説したように多くの技術が必要となります。ご紹介した技術は、たくさんある中から必要なものを取捨選択した結果ですので、当然コンテンツが変われば、必要となる技術も変わります。このコンテンツで使用した主な技術の全体図をまとめました。

使用技術概要

オンラインレースゲームというシンプルな内容のコンテンツですが、プラットフォームとしてWebブラウザを使用している点に注目していただけると嬉しいです。今までご紹介した技術は、オンラインゲームを作るだけの技術ではなく、Webコンテンツを作る上で、大きな可能性を持っている技術になります。私はゲームを作る上でこれらの技術を利用していますが、Web上の様々なサービスと連携をとることで、もっと広がりを持つコンテンツを作ることができると思います。ぜひ皆さんも、HTML5とJavaScript(クライアントサイド、サーバサイド含む)を使って、Webアプリケーションを作ってみてください。

Powered byNTT Communications

tag list

アクセシビリティ イベント エンタープライズ デザイン ハイブリッド パフォーマンス ブラウザ プログラミング マークアップ モバイル 海外 高速化 Angular2 AngularJS Canvas Chrome Cordova CSS de:code ECMAScript Edge Firefox Google Google I/O 2014 HTML5 Conference 2013 html5j IoT JavaScript Microsoft Node.js PhoneGap Polymer React Safari SkyWay TypeScript UI UX W3C W3C仕様 Webアプリ Web Components WebGL WebRTC WebSocket