JavaScriptで大量キャラ表示デモ


デモページはこちら

■ このデモについて ■

JavaScriptでアクションゲームを作ろう
 先日作ったmixiアプリ(mazename - まぜネ〜ム)は、JavaScriptでDOMを操作して表示制御を行っているのですが一見Flash?に見えるような動きを作ることができました。
 そこで、本格的にJavaScriptでアクションゲームを作れないかを実験しています。
 このデモでは、多数のキャラクターと背景を表示するデモをおこない処理性能を調べる目的で作りました。


● このデモの操作方法
 表示部分には、丸いキャラが回っているはずです。
 その下には、現在のフレームレート(fps)、設定値(インターバルタイマーの設定、キャラの数)が表示されています。
 さらにその下のボタンで設定を変更できます。
・[増やす][減らす]表示キャラの数を増減します。設定のringsの値がかわります。ringsが1あたり20個表示されます。
・[速く][遅く]処理のインサータバルを増減します。最初は10msになっていますが、こんな間隔では実際には動きません。もっと遅く(間隔を長く)すると違いがわかるとおもいます
・(ドロップダウンリスト)表示するキャラを選択できます(7種類)
・[背景を表示]チェックボックス 背景のON/OFFです

※ カーソルキーの上下左右でも設定値が変わります


ベンチマーク結果 ■

● 僕の環境ではだいたいこんな感じです。

【デスクトップ / Core2Duo E7500@2.93GHz / WindowsXP SP3】
IE6.0 36fps/200個 64fps/0個
FireFox3.6 18fps/200個 64fps/0個
Chrome4.0 107fps/200個 204fps/0個


【ThinkPadX200 / Core2Duo P8600@2.40GHz / WindowsVista SP2】
FireFox3.6 16fps/200個 90fps/0個
IE8.0 13fps/200個 64fps/0個

※ 〜個は、キャラの表示数。0の場合は表示なし


ベンチマーク結果について
結構キャラ数だしても動くものですね。
30fpsもでればアクションゲームとして成立するでしょう。
特にChrome4がムチャクチャ速くて驚きました。


【タイマーイベント発生頻度】
キャラ数0の時は、純粋なタイマーイベントの最小発生間隔を測っているようなものです。
Windowsだと64fpsくらいが上限かなとおもったら、Chromeだと204fpsまででる!そんな高頻度にタイマーイベント発生できるの?
あと、なぜかX200でのFx3.6は90fpsくらいまでリニアに追従しました。


【αとキャラのサイズの影響】
IE6がFirefox,IE8に比べ速いのはαが無効になっているためです。
それではと思い、キャラをただのGIFにしてもので試してみたのですが、結果はまったくかわりませんでした。
描画時はブラウザ内部での形式に変換されているので、もともとの画像の形式は影響しないようです。


また、意外だったのはキャラのサイズもほとんど影響しないことです。
最初は32x32pixelのキャラでテストしてましたが、その後11x11pixelのキャラに差し替えたところ、その差はわずかでした。
さらに大きなキャラに変更しても意外と速度が落ちません。
(ドロップダウンリストでキャラを変更できますので試してみてください)


処理製速度はキャラのサイズよりも、キャラの数に大きく影響されるようです。
ゲームの背景は、マップチップを並べて表示するより大きな1枚絵で表示したほうが高速になるようです。
ベンチマーク中、背景のON/OFFができますが、処理速度にはほとんど影響しません。1773x1139の大きめのイメージを使っていますが、描画自体は見えているところだけされるためもと画像のサイズはあまり影響しないようですね。

openspc @fslasht BGは低速になるので巨大な一枚絵がいいですよ。ただ、これもFirefoxは32768ピクセルだったか、16384だったか制限があったかなと。SafariだとFirefoxより巨大な画像でもいいんですが。(巨大なグーグル一枚マップの時にサイズ制限発覚)



● 他の環境のベンチマーク
iPhoneHT-03Aでも動いたそうです。
古籏さんがMacベンチマークしていただきました。他にも有益なアドバイスはいただきました。ありがとうございます。

openspc @fslasht うちだとMacProだけどFirefox3.6が16fps, Opera 10.10が30fps, Safari 4が50fps, Chrome 5が75fpsくらいでした。Firefoxが低速すぎみたいです。

他の環境のベンチマークとれたらぜひ教えてください。



■ 技術的なはなし ■

● このデモのソースなどは・・・
ここにあるのがすべてですので、適当に持っていってください。
何かの参考になれば幸いです。


canvasは今回つかわない
ゲームみたいな不定数のキャラを描画するなら、Canvasに描画するのが素直だと思いますが、IEで対応していないしね・・・
Canvas.js使えばIEでもエミュレートして使えるけど、かなり遅くなる・・・
速くCanvasネィティブで対応してよ。


● DOM vs innerHTML
mazenameでは、予めHTMLで配置したキャラをDOM操作で動かしてます。
でも、ゲーム以下の点がDOMでは不利なのではないかと考えました。
【DOMの不利っぽいところ。たぶん】
・DOM操作ってなんか遅そう(そうではないという説もある)
・動的にキャラ数変わるのでDOMでは面倒(キャラ生死意外に画面への出入でも頻繁かわる)
・多数のキャラがある場合、順番にDOM操作してると一斉に動いているように見えないのでは?(背景とキャラがずれたり)


というわけで、今回は、javaScriptでHTML(imgタグがいっぱい並んだもの)を毎回生成して、表示エリアのdivのinnerHTMLを更新してます。

var str="";
for ( var j=0; j<m_rings; j++ ) {
for ( var i=0; i<20; i++ ) {
r = m_count + i*18;
d = 180 - j*(m_rings<4 ? 40 : 10 );
x = 200+Math.cos(r/180*3.141)*d -16;
y = 200+Math.sin(r/180*3.141)*d -16;
str += '<img class="chr" style="top:' +y + 'px; left:' +x+'px;" src="' +filename+ '">';
}
}
stage_frame.document.getElementById("stage").innerHTML=str;


こんなんでそれなりに動いているのでまあいいかな。
ただし、このまま背景に巨大イメージを入れようとしたらちらついたり表示されなかったり上手くいきませんでした(ブラウザの機嫌がいいとき=キャッシュが効くときはちゃんと表示された)。
どうやら、InnerHTMLを直接書き換えるということは、書き換え前にその中で使われていたimgのsrc画像が一旦クリアされ、再読み込みされているようです。
毎回、背景画像を読み込むことになってしまいうまく表示されなかったのだと思います。
(小さなイメージはキャッシュが効くのか、見かけ上問題はなさげ)
とにかく、画面上からイメージが全部なくなっちゃうと読み直しが発生するようです。
これは、画面外に同一の画像をダミーで配置しておおくことで、回避できました。


とはいえ、なんかきもちわるいので、このデモでは背景画像だけはHTMLに常設してDOMで操作してます。


※サーバにアップして試してみたけど、ブラウザによってとんでもない勢いでサーバにリクエスト送らないか?この方法・・・



● 文字列処理に意外と時間かかる
開発中のベンチとして、javaScriptでHTMLを生成するだけでinnerHTMLには書き込まないテストをしてみました。
そうしたところ、作成あり(200個)/なし(0個)では、85fps / 94fpsの違いがありました。(Firefoxにおいて)


innerHTMLに書き込む文字列を作成するのにも時間がかかっているようです。
以下の記事を読んだので、HTMLを生成するときは単純に += や + で文字列を連結しているのですが、これでは遅いのかなあ。
JavaScript文字列処理は"+="が十分高速、Safariもベター



● キー入力
 ブザウザによって処理方法が違ってメンドイですね・・・
 以下のブログ記事が大変参考になりました。キーコード表が便利!
各ブラウザでキーコードを取得してみた【JavaScript】


● IFRAME
 ページの一部をゲーム表示エリアにしたい。
 そのために、divで枠を作ってみた(widthとheightを指定して)のはいいですが、imgの表示位置(position)をabsoluteにするとページ全体の左上からの位置になっちゃうし、relativeにするとなんか思ったようにいかない(重なるとずれるし)。
 そこで、ベージ内にIFRAME切ってその中に、ゲーム画面をつくりました。
 IFRAME中のHTMLは、別に用意しないでjavaScriptで生成してます。
 IFRAMEへのアクセスがナンですが。そもそも、IFRAMEの中でフツーにJavaScriptを動かした方がいいような気がしますね。
 今のところ以下の問題アリ


IE6.0→iframeにファーカスがあるとキーが効かない
Chrome4.0→iframeに縦スクロールバーが出てしまう


Flash vs JavaScript
そんなこんなで苦労してJavaScriptやってますが、素直にFlash使えば?という説も・・・
Flashのよいとこ】
・環境依存の動作の違いが殆どない
・パフォーマンスが高い
・表現力が高い
 ・ベクターグラフィックス
 ・イメージは拡大縮小回転もできる
 ・フォントが綺麗
 ・ビデオも再生できる
・音を出せる
・オーサリング環境が素敵


Flashのよくないところ】
iPhoneとかでうごかない(今度のFlashではアプリを生成できるようだけど)
Flashのオーサリングソフトは有償(買えば良い。あるいはFlexつかえばいいか)


JavaScriptのよいとこ】
・なんとなくお手軽感がある
・これからはHTML5+javaScriptだとGoogle様も言っている
・ほとんどのブラウザで動く。iPhoneでも動く※でも挙動が環境ごとに違いすぎるが…
・そこそこ性能はでる
・表示はHTML/CSSで記述できる
・ソース書いたらコンパイルしないでそのまま動く
Firebugデバッグできる
・普通のWebプログラムでも使うしね


JavaScriptのよくないところ】
(いっぱいある)
・環境依存おおすぎ/性能もまちまち
・表現力がHTML/CSSで記述できるところまでしかできない
・やっぱそんなに速くない
・音が出せない(音だけFlashを使うかw)


まだまだいろいろありそうだけどこんな感じかな。
でも、FlashJavaScriptもお互いに連携する機能はあるので、仲良くやりましょうってとこで