HTML5ゲームEaselJS編そして真の敵

画像の表示にはEaselJSというライブラリを使用しました。こいつはいい。完成度が高いし使いやすい。まあ、JavaScriptでこういうライブラリを作るってのは、マッチ棒で五重塔を作るような曲芸のような気もするし、そのパワーを他のプロダクトに向けたら世界が変わったんじゃないかと(以下略

EaselJSについては、今更私ゴトキが言及するまでもないんですが、いろいろと引っかかったところもあったので参考までに。


ベクター画像の描画は遅い

Flash Pro CS6のToolkit for CreateJSというツールを使うと、ライブラリのシンボルをEaselJS用に書き出すことができます。書きだしたファイルはJavaScriptになっていて、シンボル単位でクラスにまとめてある。こいつを追加しておけば、たとえばcoinshapeというリンケージ名をつけているシンボルなら、

var myshape = new lib.coinshape();

と書くだけで生成できます。簡単!

しかしこのデータはベクターなんですね。ソースを見てみると、HTML5のCanvas用描画コマンドが、圧縮された形で延々と並んでます。そのため描画し直すたびに点とか線とか塗りつぶしとかを繰り返すため超遅い。
そういうとき、Flashだったら一時的にビットマップ画像にキャッシュしておくオプションがあったハズ。そうcacheAsBitmapですな。こいつをtrueにしておけば、変形とか回転さえしなければ高速にレンダリングしてくれた。
EaselJSにはこのオプションはないものの、少し似てるのがあります。それがキャッシュ。ベクター画像を描画後に、範囲を指定してcacheという命令を実行すると、その範囲をビットマップ画像に切り出して代わりに使ってくれる。しかも回転や拡大なんかもそのまま使ってくれるんで処理速度が落ちない(けど画質は当然落ちる)。たとえばこんな感じ。

var myshape = new lib.coinshape();
myshape.x = 0;
myshape.y = 0;
myshape.cache(0,0, 32,32);

最初からビットマップ画像を読み込んだ場合は、こういう処理は必要ありません。たとえば、

 

var myBitmap = new Bitmap(“images/top.png”);

が、外部ファイルを読んだ時は読み込みが完了しないと画像サイズとかは拾えないので注意。onLoadとかで読み込み完了を拾うこと。数が多い時はPreloadJSの利用を検討したほうがラク。

それとこのcacheはフィルタを利用するときにも使うんだけど、cacheAsBitmap的なオンオフ・フラグと認識してるとハマる。こいつはオフスクリーンに画像をコピーする命令だと思ってください。フィルターを適用するときも、filtersプロパティにフィルタをセットした「後」でcacheを実行すること。このときに実際の処理が行われてオフスクリーンにフィルタ付き画像が生成されるから。

マウスイベントがちょっとアレ

ここもブラウザーの非互換で悩まされるところで、Android版のFireFoxは消えてほしい(が4.2でもFlashが動くので消えないで)。
それはともかく、ちょっと注意が必要。

まず、someObjectの中のシェイプか何かにマウスイベントを登録したとしますよね。

myshape.onPress = this.onPress;

みたいに。で、onPressを実装。

someObject.prototype.onPress = function (event) {
    var who = this;
    console.log(who);
}

まず、いきなりだけど最初のところで、whoは誰になるのかと。何って、そりゃあsomeObject自身でしょうと思ったら大間違いで、もちろんmyshapeなわけです。だってmyshapeがクリックされて発生するイベントを受け取ってるんだもん。これがJavaScriptの仕様。普通だったらthisはsomeObjectになるよね。じゃないと自分のプロパティにアクセスできないもん。

これこそがJavaScriptの言語仕様の致命的な実装ミスであり、このミスのためにどんだけこの言語が誤解されているか考えると悲しくなりますが、まあ私はJavaScriptなんか嫌いなのでどうでもよろしい。これにはこれで色んな理由があるんだろうし関わりたくない。なぜ豚肉を食べないかとか、そういうのには興味が無い。

そんなことより、物理演算ライブラリを使ってる場合なんかで、画面に表示されているシェイプと、仮想空間上で移動しているボディの両方を一つのクラスで扱っている場合は、お互いのプロパティにアクセス可能にしておかなければならないんですよ。さてどうするか。

一番簡単な方法は、

myshape.self = this;

と初期化の時に書いて自分自身への参照をシェイプに登録しておき、マウスイベントが呼ばれた時に

var self = this.self;    //thisはmyshapeを指してる

とselfに代入してやる。で、selfをthisの代わりに使う。こういうところは柔軟だね。

audio、お前はダメだ

EaselJSとHTML5のCanvasに関しては、ものすごく遅いことを除けば不満は少なかったです。超イライラしましたが。ああ、そうだ。CanvasってHTMLの要素なんで重ねることができるんですよ。たとえば新幹線ゲームではこんな感じ。2枚使ってます。

<div style=”position: relative;”>
<canvas id=”bg” width=”640″ height=”800″ style=”position: absolute; left: 0; top: 0; z-index: 0;”></canvas>
<canvas id=”fg” width=”640″ height=”800″ style=”position: absolute; left: 0; top: 0; z-index: 1;”></canvas>
</div>

このidがbgのほうに、盤面の背景を描いてます。つまり背景の描画はブラウザーに任せたわけね。少しは速くなるかと思ったけど大差ないな。ブラウザー側がハード的に合成してくれればもう少し効果が出るでしょう。あと、多重スクロールなんかで、更新間隔が違うものを後ろに分離すれば多少は処理速度が上がるかも。試してみて。

いやいや、そんなことよりaudioタグですよ。もう最悪だよ。音を鳴らすための仕組みだよ。

まずモバイルブラウザのaudioタグの仕様がひどい。iPhoneで言うと、同時に鳴らせるのは1音だけ。しかも音データを事前に読み込めない。ユーザーがクリックしたときだけ。別の音を鳴らすと前の音オブジェクトは破棄される。

その結果、鳴らすたびに読み込みが発生し動きが止まる。タイミングが大幅にずれる。

Androidのブラウザーに至っては、1秒以下のタイミングで制御すると不安定になるは、そもそも制御できないとか鳴らないとか、ブラウザーによって動作がマチマチな上に非常に完成度が低い。まだ仕様が決まってないからなんて言い訳が通用しないくらいひどい。なんだよこれは。

なので仕方なく、すべての効果音をつないで1つのサウンドファイルにし、再生位置をシークさせて鳴らしてるんですよ。なんだよもう。スーファミで雲のキャラを使いまわしてるんじゃないんだから。

この辺をなんとか使えるようにしたUnitePlayer.jsというのもあるので興味のある方はどうぞ。BGMまで使えるように工夫している。すごいね。

http://uupaa.hatenablog.com/entry/2011/12/12/213233

他にも、タッチイベントなんかもブラウザーごとに処理がマチマチで、Android版のFireFoxなんかだと正常に動作しない。こいつはCanvasへの描画も遅いし、何をやってるんだろう。
HTML5の仕様策定が終わったから2014年に正式勧告するよなんて記事が出てたけど、いったいいつの話なんだよと。

 

ジョブズがFlashに死刑宣告をしたとき、彼はこんなことを言っている。

われわれの動機は単純だ。それは当社のデベロッパーに最先端のもっとも革新的なプラットフォームを提供することであり、デベロッパーには世界で誰も見たことのない最高のアプリを、直接このプラットフォームの上で作ってもらいたい。われわれはデベロッパーが今以上にすばらしい、強力な、楽しい、有用なアプリケーションを作れるよう、このプラットフォームを強化し続けていきたい。全員が勝者になれる。最高のアプリのおかげでわれわれのデバイスがさらに売れ、どのプラットフォームよりもすばらしく幅広いアプリの品揃えのおかげでユーザーは喜びをえられる。
(TechCrunch Japanから引用:http://jp.techcrunch.com/archives/20120630steve-jobs-war-against-flash/

それから2年以上たったけど、どこにそんな革新的なプラットフォームがあるんだよこら。というか、ここまで大見得を切ったのなら、みんなが唸るほどのものをさっさと出せよ。それこそFlashなんてバカらしくて使ってられないような開発環境と再生環境を。

 

なんてね。マップやiOS6を見れば、そういう技術が今のアップルにないことはもうわかってるんだ。それこそMac Plusを売ってた頃からそうだったもん。この会社には得意なこととそうでない事がある。ジョブズは自分の好き嫌いと、会社の利益の事しか考えてない奴で、全部自分たちだけで作ろうと怒鳴り散らす男だった。でもダメなら誰かに頭を下げて(あるいは脅迫して)作ってもらうくらいのズルさはあったし、こっそり取り下げる位の事はやった。今のアップルにはもうそんな腹芸は無理だろうな。

そうなるとますますHTML5とJavaScriptの未来は、学生の玩具かベンチャーが企業から金を引っ張る魔法の杖にしかならないんじゃないか。せいぜいスマートフォン用のローカルな規格とか。そして今後何年も、非互換性やらを回避するバッドノウハウをいろんなスクリプトが実装し、それ同士が衝突し。今回、JavaScriptでゲームを作ってみて得た結論はこれです。最近の私がご機嫌ナナメな理由もこれです。

ま、私の未来予想なんて当たったためしはないし、今より悪くなることもないから、そんなに悲観する必要はない。ビジネスとしては厳しいけど(逆か。大変だからビジネスになるのか)、趣味で遊ぶなら楽しいこともわかった。だいたいの動作速度や開発サイクルも皮膚感覚として理解した。それでヨシといたしましょう。今年の総括は以上!

コメント / トラックバック1件

  1. […] >>HTML5ゲームEaselJS編そして真の敵 « ど~でもインスタンス Author: […]