2012年8月25日土曜日

websocket + HTML5(canvas)でのゲーム開発(ボンバーマン風)

このエントリーをはてなブックマークに追加

はじめに

エンジニアの@ryooo321です。
よろしくお願いします。

Happy Elements株式会社では勉強会が活発に行われており、
その中の1つに「1.5時間で○○を作る」エンジニア向けワークショップがあります。(毎週開催@京都)
※ ○○は毎週かわり、設計/実装方法などは自由です。

今回はワークショップ2回(計3時間)で作成したボンバーマン風ゲームの紹介を通して、
他人とリアルタイムで遊べるゲームの可能性を感じていただければと思います。
※ 技術的にはwebsocket、canvasを利用
※ ライブラリ/ツールとしてNode.js、CreateJS、socket.io、coffeescriptを利用
※ 急いで作ったのでほとんどリファクタリングされていませんmm

また、おまけとして
サーバーサイドでのcanvas描画とwebsocketでのバイナリメッセージについて
試してみた結果を共有します。

ボンバーマン風

紹介

基本的にはcanvasで表示する形のゲームですが、
websocketを使って異なる端末・ブラウザで描画情報を同期しています。
下記程度のアウトプットを、338行程度のコーディングで可能でした。

※ わかりづらいですが、2つのブラウザで2キャラが操作できており、表示が同期しています。
※ 動画内consoleに流れているのがwebsocketの通信データです。

ソース

説明

1. サーバーサイド(server.coffee)
マップや爆弾や敵、キャラや炎などあらゆるオブジェクトはNodeサーバー上に持っています。
Nodeサーバーは10回/秒のペースで、canvas描画情報をブラウザにpushしています。(描画差分のみ)

サーバー起動時にマップを作成するので、
起動後にアクセスしたユーザーは同じマップで遊ぶことになります。

2. クライアントサイド(public/javascripts/client.coffee)
ブラウザはCreateJSを使ってcanvasに描画するだけです。
画面全体の描画をさけるために静的要素のcanvasと頻繁に書き変わる要素のcanvasを分けました。
静的要素(芝/石)のcanvasは初回のみ描画するようにすることで付加軽減を図っています。
※ キャラ、敵、炎、爆弾の変更情報のみ通信しています。

所感

[CreateJSすごい]
CreateJS(Easel.js)を使うとcanvas操作が驚くほど楽になりました。
(enchant.js以来の衝撃でした++)

[安定のcoffeescript]
coffeescriptを使うことでクラス化やリファクタリングが楽になり、
単純にタイピング量も減りました。

[websocketはリアルタイムで有利に感じました]
websocketを使うとhttpで同じ回数通信するより通信量が少なくなるので、
大規模にやるならwebsocketは有利だと思います。
しかし、この程度のjsonデータ量であれば規模によっては
ブラウザから同じ回数のAPIリクエストを飛ばしてもよいかもしれません。
500qpsさばける構成なら50人が同時接続しても問題ないかもしれません。
(1クライアントあたり10qpsとして)(簡単なjsonを取ってくるだけなので今のつくりでは重くはありません)


おまけ - サーバーサイドでのcanvas描画

概要

サーバーサイドがjavascriptなので、サーバーでcanvas描画しbitmapをブラウザに転送してみました。
ついでにバイナリでのwebsocket通信もやってみました。
ボンバーマン風で使ったwebsocketライブラリ(socket.io)は現時点でバイナリメッセージに対応していないので、代わりにnode-websocketを利用しました。

ソース

説明

下記でcanvasが使えるようになります。
brew install cairo
brew link cairo
npm install canvas
node.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

一緒に働きたい方、絶賛 募集中
京都で開発してみたいというエンジニアの皆さん、ご応募お待ちしています!
技術力を伸ばしたい学生さん、アルバイトも可能なのでご応募お待ちしています!
大阪、滋賀、神戸から通勤実績あり


以上、長文にお付き合い下さいましてありがとうございました。

9 件のコメント:

  1. Dự án chung cư Legend Tower Nguyễn Tuân
    Dự án chung cư Việt Đức Complex Khuất Duy Tiến
    Căn hộ BRG Park Residence Lê Văn Lương
    Mở bán chung cư Rivera Park Vũ Trọng Phụng
    Ra mắt Paragon Tower Phạm Hùng Cầu Giấy
    Căn hộ cao cấp Chung cư Royal Park Lê Văn Thiêm
    Chung cư Xuân Mai Sparks Tower Dương Nội
    Chung cư Dự án Thanh Xuân Complex số 6 Lê Văn Thiêm

    返信削除
  2. このコメントは投稿者によって削除されました。

    返信削除
  3. โปรโมชั่น[url=https://www.gclub45.com/]Gclub[/url] ของทางทีมงานตอนนี้แจกฟรีโบนัส 50%
    เพียงแค่คุณ[url=https://www.gclub45.com/]สมัคร Gclub[/url] กับทางทีมงานของเราเพียงเท่านั้น
    ร่วมมาเป็นส่วนหนึ่งกับเว็บไซต์คาสิโนออนไลน์ของเราได้เลยค่ะ
    สมัครสล็อตออนไลน์ >>>[url=https://www.gclub45.com/goldenslot.html]Goldenslot[/url]
    สนใจร่วมลงทุนกับเรา [url=https://www.gclub45.com/agent-gclub.html]สมัครเอเย่น Gclub[/url]คลิ๊กได้เลย

    返信削除
  4. โปรโมชั่นGclub ของทางทีมงานตอนนี้แจกฟรีโบนัส 50%
    เพียงแค่คุณสมัคร Gclub กับทางทีมงานของเราเพียงเท่านั้น
    ร่วมมาเป็นส่วนหนึ่งกับเว็บไซต์คาสิโนออนไลน์ของเราได้เลยค่ะ
    สมัครสล็อตออนไลน์ >>> goldenslot
    สนใจร่วมลงทุนกับเรา สมัครเอเย่น Gclub คลิ๊กได้เลย

    返信削除
  5. เว็บไซต์คาสิโนออนไลน์ที่ได้คุณภาพอับดับ 1 ของประเทศ
    เป็นเว็บไซต์การพนันออนไลน์ที่มีคนมา สมัคร Gclub Royal1688
    และยังมีหวยให้คุณได้เล่น สมัครหวยออนไลน์ ได้เลย
    สมัครสมาชิกที่นี่ >>> Gclub Royal1688
    ร่วมลงทุนสมัครเอเย่นคาสิโนกับทีมงานของเราได้เลย

    返信削除