websocket + HTML5(canvas)でのゲーム開発(ボンバーマン風)
はじめに
エンジニアの@ryooo321です。
よろしくお願いします。
Happy Elements株式会社では勉強会が活発に行われており、
その中の1つに「1.5時間で○○を作る」エンジニア向けワークショップがあります。(毎週開催@京都)
※ ○○は毎週かわり、設計/実装方法などは自由です。
今回はワークショップ2回(計3時間)で作成したボンバーマン風ゲームの紹介を通して、
他人とリアルタイムで遊べるゲームの可能性を感じていただければと思います。
※ 技術的にはwebsocket、canvasを利用
※ ライブラリ/ツールとしてNode.js、CreateJS、socket.io、coffeescriptを利用
※ 急いで作ったのでほとんどリファクタリングされていませんmm
また、おまけとして
サーバーサイドでのcanvas描画とwebsocketでのバイナリメッセージについて
試してみた結果を共有します。
ボンバーマン風
紹介
※ わかりづらいですが、2つのブラウザで2キャラが操作できており、表示が同期しています。
※ 動画内consoleに流れているのがwebsocketの通信データです。
ソース
説明
マップや爆弾や敵、キャラや炎などあらゆるオブジェクトはNodeサーバー上に持っています。
Nodeサーバーは10回/秒のペースで、canvas描画情報をブラウザにpushしています。(描画差分のみ)
サーバー起動時にマップを作成するので、
起動後にアクセスしたユーザーは同じマップで遊ぶことになります。
2. クライアントサイド(public/javascripts/client.coffee)
ブラウザはCreateJSを使ってcanvasに描画するだけです。
画面全体の描画をさけるために静的要素のcanvasと頻繁に書き変わる要素のcanvasを分けました。
静的要素(芝/石)のcanvasは初回のみ描画するようにすることで付加軽減を図っています。
※ キャラ、敵、炎、爆弾の変更情報のみ通信しています。
所感
CreateJS(Easel.js)を使うとcanvas操作が驚くほど楽になりました。
[安定のcoffeescript]
[websocketはリアルタイムで有利に感じました]
おまけ - サーバーサイドでのcanvas描画
概要
ついでにバイナリでのwebsocket通信もやってみました。
ボンバーマン風で使ったwebsocketライブラリ(socket.io)は現時点でバイナリメッセージに対応していないので、代わりにnode-websocketを利用しました。
ソース
説明
brew install cairo brew link cairo npm install canvasnode.js内では
下記でcontextがとれ、描画できます。
Canvas = require('canvas') canvas = new Canvas(400, 400) ctx = canvas.getContext("2d")描画したcontextは、下記いずれかの方法でブラウザで利用できます。(きっと他にもあります)
1. base64エンコードしてwebsocketでpush
socket.sendUTF(canvas.toDataURL())2. bitmapの色情報のbyte情報をwebsocket(ArrayBuffer)でpush
imagedata = c.getImageData(0, 0, 400, 400) bin = imagedata.data len = bin.length buff = new Buffer(len) for i in [0..(len-1)] buff[i] = bin[i] socket.sendBytes(buff)3. 画像ファイルとしてサーバーに保存して、ブラウザからhttpリクエスト
# 実装例は割愛
所感
サーバーサイドcanvasについては、あまり有用とは感じませんでした。
素直にブラウザでやればよいと思います。
canvasで描画した画像をブラウザに送る形にすることで、
ブラウザ側の処理を軽減できるケースがあるとは思います。
SmartPhoneなどのパワーのない端末で巨大なcanvasを使いたい場合などは、
サーバーで大きなcanvasを作成して一部分だけcontext.getImageData()して転送したりもできそう。
[もっといろいろできる]
バイナリメッセージを使えば、音楽・動画も他人と簡単に共有できるようです。
WebSocketのバイナリメッセージを試したら、ウェブの未来が垣間見えた
[ライブラリ利用]
サーバーサイドでCreateJSを使うにはwindowオブジェクトやdocumentオブジェクトを
Node.jsに組み込まなければなりません。
しかし、jsdomを入れるすることでCreateJSやjQueryも利用できるはずです。
※ jsdomは、nodeの環境にW3C準拠のdomオブジェクト群を定義してくれるライブラリです。
[データサイズ]
bitmapは1ピクセルに4byte使うので、縦横400pxでは640,000byteほどのbitmap配列になります。
これをwebsocketで転送してブラウザで表示するには1push/sが限度でしたorz
一方、今回の例では透明領域の大きい画像だったこともあり、
base64にエンコードする方法だと2,000byte程度でした。
これだと、100push/sでもさくさく表示できました。
※ localhostのサーバーです。感覚値で恐縮です。
[Blobでの通信]
ArrayBufferでなくBlobで通信するバイナリメッセージもあり、
canvasでない場合はBlobで通信した方が早いでしょうね。
画像ファイルをBlob転送してみましたが大きくてもざっと問題なさそうでした。
関連情報
・Node.js
http://nodejs.org/
・CreateJS
http://createjs.com/#!/CreateJS
・coffeescript
http://coffeescript.org/
・websocket
http://www.html5.jp/trans/w3c_websockets.html
http://tools.ietf.org/html/rfc6455
・socket.io
http://socket.io/
・jsdom
https://github.com/tmpvar/jsdom
一緒に働きたい方、絶賛 募集中
京都で開発してみたいというエンジニアの皆さん、ご応募お待ちしています!
技術力を伸ばしたい学生さん、アルバイトも可能なのでご応募お待ちしています!
大阪、滋賀、神戸から通勤実績あり
以上、長文にお付き合い下さいましてありがとうございました。