fslashtの日記: JavaScriptで大量キャラ表示デモ 15
■ このデモについて ■
● 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の大きめのイメージを使っていますが、描画自体は見えているところだけされるためもと画像のサイズはあまり影響しないようですね。
● 他の環境のベンチマーク
iPhone、HT-03Aでも動いたそうです。
古籏さんがMacでベンチマークしていただきました。他にも有益なアドバイスはいただきました。ありがとうございます。
他の環境のベンチマークとれたらぜひ教えてください。
■ 技術的なはなし ■
● このデモのソースなどは・・・
ここにあるのがすべてですので、適当に持っていってください。
何かの参考になれば幸いです。
● 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)
まだまだいろいろありそうだけどこんな感じかな。
でも、FlashもJavaScriptもお互いに連携する機能はあるので、仲良くやりましょうってとこで
JavaScriptでアクションゲーム (スコア:2)
昔からその手のことを考えていらっしゃる人がいてまして・・・
#昔はコンパイラ等が何万円もして・・・TT
10年以上前は雑誌等に収緑されていましたが、PCスペックが追いつかない(&環境依存が現在よりも強すぎた)ために普及しませんでした。
2003年くらいにやっと実用的に動き出し始めましたが、動作が遅いというマイナスイメージをいまだに払拭できずにいます。
※一般的なPCスペックが良くなったため
#さすがに他の手段より遅いですがw
有名どころでは、JavaScript実装のスーパーマリオがありますが、格闘ゲーム系も結構あります。
#MMORPGのようなものも簡単な実装はあったような・・・
実際に研究・実装してみるとわかるかと思いますが、画像データ等は別ファイルで用意する必要はありません。利便性をとってするくらいです。
私はあまりクリエイティブではないので、fslashtさんに期待しています(何をw
#ACにしようかどうか迷ったけどIDにしておこう
Re:JavaScriptでアクションゲーム (スコア:2)
いまでは、GoogleDocsが実用になるくらいの性能ありますものね。一昔からは考えられないことです。
JavaScriptでのアクションゲーム、マリオとか僕からみると黒魔術級です。
イメージを並べてるわけではなさそうなので、動的にイメージを作ってるんでしょうね。
イメージそのものを生成できればブラウザ間の差異がほとんどなくなるからいいなあ。
思い当たるのは「data スキーム」くらいなのですが、これだとIEでは対応してないし・・・。CanvasもIEは非対応だし。
どうやってるんだろう。
なにかご存知でしたらご教示いただけたら幸いです。
HTML/CSSをいじるのも面白いので、現状の路線もこれはこれで続けてみようとおもいます。
汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:1)
Konqueror(3.5)で輪が一つでも10fps程度。遅い。
FireFoxでは20fpsくらい出てたけど、背景が前に出ててキャラが隠れる。
両方とも背景がやたら重い。
Javaの方が速くない?
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:2)
WinでもIE系だと背景が前にきちゃって困った。
背景有無は速度にほとんど影響ないけど、Linux版Fxとかだと影響するのか・・・あと、LinuxだとFxでも背景前にきちゃうのか。うむむ
他に速い技術はいろいろあるだろうけど、JavaAppletだとプラグイン要るから避けたいんですよね~
でもFxで200個で20fpsでてれば性能的には十分だな。背景のバグさえとれれば
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:1)
背景が影響するのはアクセラレーションの効きかも試練。
...Javascriptはブラウザ依存の嵐で大変だぞー。
で、ソース読んだけど...毎回ページ生成してたらそら遅いよ。
キャラの箱を最初から用意して属性だけ変えてった方が速くない?.style.leftとか.style.topとか。
# 試してはいないからそれでちゃんと動くと断言できんけど。
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:2)
ちょっと修正、背景が前に来ちゃうのは直ったはず(backgroud-imageで表示するようにした)。
とりあえず各ブラウザで差異がでるところは箇所はこれで解決かなあ。
DOMでやるのとinnerHTMLでやるのどっちが速いかなんだけど、これは試してみないといけないと思ってる。
DOMだと大量のキャラを一度に動かすとき、画面上でどう見えるかわからない(順番に動かしてるの見えちゃうかもしれないし)んで、ちょっと躊躇。(mazename作ったときは10個しかなかったので気にならなかった)
まあ、試してみるかー
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:1)
直ってる。けど5fpsくらいだなぁ...。
で、ちょっと作ってみてるんだけど、なかなかうまく行かず。
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:2)
Konquerorで5fps?遅いなあ。Firefoxならもうちょっと速いかも。
大変非力なArm 800MHzなNetWalker上のFirefox3.0/Ubuntu でも2.1fpsはでてるよ。
DOM操作版の成果に期待
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:1)
んにゃ。Firefoxで。
そしてDOM板は飽きた(ぉ
そして手抜き極まりないブツ->http://woyashiki.tarosuke.net/charatest.html [tarosuke.net]
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:2)
おお~
これはスムースに動いてますね>DOM版
そうかぁ DOMでも表示がおかしくなることはないんだな・・・
tarosukeさんの環境では、どれくらい速くなりましたか?
Re:汗64かなり古い(2800だっけか)/GentooLinux(64)で (スコア:1)
「ちょっとうねうねするけど速くなった気がする」くらいしかわからんです。
計測コードが入ってないし背景動かしてないし128個だしで、比較はできませんな(ダメヂャン
# ちょっと増やしてみる。
LinuxでもChromiumだと速いっぽい (スコア:1)
周回遅れながら報告。
tarosukeさんのところと結構環境が被りますが、こんな感じで。
CPU: Opteron 2350
OS: Gentoo Linux amd64
ブラウザ:
Chromium (5.0.307.9)
Konqueror (4.3.4)
Firefox (3.5.6)
デフォルト表示ではこうなりました。
Chromium: 90fps
Konqueror: 20fps
Firefox: 15fps
interval = 10ms, rings = 0だと、
Chromium: 92〜93fps
Konqueror: 100fps
Firefox: 95fps
interval = 0ms, rings = 0だと、
Chromium: 210fps
Konqueror: 100fps
Firefox: 95fps
Chromiumが抜きん出ています。
あと、Firefoxのfpsが安定しません。適当に平均ぽい数字を書きましたが、例えば95fpsと書いたところでは20〜100あたりを行ったり来たり。
ちなみにどのブラウザもマルチスレッドで動いている様子はなし。やたらとコアを積んでますが、それはあまり関係ない模様。
ところで、大抵のブラウザの実装ではタイマー精度が10ms程度なのに対して、Chromeは1msの精度を持つ、という検証記事(Blogだったかも)をどこかで見たことが。
ノーウェイトでChrome/Chromiumがやたらとfpsが上がるのはその辺の事情によるのかな?
巧妙に潜伏したバグは心霊現象と区別が付かない。
Re:LinuxでもChromiumだと速いっぽい (スコア:2)
検証ありがとうございます。
Chromiumはダントツですね~
mixiのほうでSafari@Macのベンチ結果もChromeほどはいきませんがかなり速かったです。WebKit系速いなぁ
タイマー精度たかいのはようやってるんだろう。WindowsでもWM_TIMERとかじゃこんな精度でないので、専用のワーカスレッドからイベント発生させてるのかな。
Firefoxのfpsが安定しないのは、GCの時に一瞬固まるからのようです。
これについては、今日の日記で追加説明を書きました。
DOM操作版も作ってみましたが、こちらはfpsもあがり停止時間も短くなっていい感じです。
プロセスはWindowsでも1コアしか使ってくれないみたいですね。
HTML5で追加される「Web Workers」という機能を使う [progress.from.tv]とマルチコア活用出来るようです。
音は出せます (スコア:0)
> ・音が出せない
つ[HTML5 audio]
HTMLのaudio要素として使うほか、もっとJavaScriptからnew Audio();のようにして初期化もできます。
IEだとbgsound要素をJavaScriptから操作して何とかするんでしょうか? 知らないけど。
Re:音は出せます (スコア:2)
HTML5 audioを忘れてました。videoもOKですね。
これなら簡単に出来そうです。
IEさんの場合は・・・bgsoundでできるみたいですね。サンプル見つけたので使ってみます。