<iframe style="width: 124px; height: 20px" class="twitter-share-button twitter-count-horizontal" title="Twitter Tweet Button" src="http://platform.twitter.com/widgets/tweet_button.1340179658.html#_=1340787831530&count=horizontal&id=twitter-widget-0&lang=ja&original_referer=http%3A%2F%2Fjapan.internet.com%2Fwebtech%2F20120627%2F1-2.html&size=m&text=%E3%80%90HTML5%20Dev%E3%80%91%E3%82%B2%E3%83%BC%E3%83%A0%E3%80%8CCut%20the%20Rope%E3%80%8D%E3%82%92%20Web%20%E3%82%A2%E3%83%97%E3%83%AA%E3%81%A7%E5%86%8D%E7%8F%BE(2%2F6)%20-%20%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%82%B3%E3%83%A0&url=http%3A%2F%2Fjapan.internet.com%2Fwebtech%2F20120627%2F1.html&via=jic_news" frameBorder=0 scrolling=no></iframe>
Objective-C から JavaScript へ
Cut the Rope を新たなプラットフォームへ移植するにあたり、ユニークな物理シミュレーション、動作、独特な操作感は絶対に維持したかった。そこでわれわれは作業の早い段階で、元々の iOS バージョンを(書き直すのではなく)「移植」する形で取り組もうと決めた。オリジナルの Objective-C コードを広範に調査するところから取りかかったが、それにより、このゲームが大規模で複雑なものであると判明した。なんとオリジナル iOS バージョンは、ライブラリを除いても約1万5,000行のコードでできていたのだ。コードのなかで最も複雑な部分は、物理シミュレーション、アニメーション、描画エンジンだった。これらは単体でも複雑だが、3つすべてが密接に連携し、高度に最適化されていることで、一段と複雑さを増していた。
そのユニークな個性とゲームマニアに馴染みのある極めて高い品質を維持しつつコードを Web ブラウザに移植することは、気が遠くなるような作業だった。実現に向けて頼りにしたのが JavaScript である。
かつて JavaScript は速度の遅い言語とみなされていた。率直なところ、当初その評判は正しかった。古い JavaScript エンジンは、シンプルな(その名前の由来でもある)「スクリプト」系の作業向けに設計されていた。だが、現在の JavaScript エンジンは、高度に最適化されている。JIT コンパイルなどの機能により、現在の JavaScript はネイティブ言語に近い速度で実行できるようになっている。
それ以外に、JavaScript のコーディング方法がコンパイラ言語のそれと違うこと(そして異なる思考が必要なこと)も分かっている。Objective-C ベースのゲームを移植する過程で、そうした変更や最適化に対応する必要が生ずることは予想していた。
分かりやすい例を紹介しよう。JavaScript には、構造体がないのだ。構造体は、関連性のあるプロパティを単純に一まとめにするデータ形式である。JavaScript のオブジェクトを使えば構造体的なプロパティ セットは実現できるものの、この対処法と本来の構造体には重要な違いがある。 1つ目の相違は、変数への割り当てや関数へのデータ渡しが行われる際、構造体のコピーに対して処理が行われる点だ。そのため、Objective-C のようなコンパイラ言語で書かれた関数は、呼び出し側の値に影響を与えることなくパラメータとして渡された構造体を変更できる。関数内でさえ、異なる変数に構造体を割り当てるとその値がコピーされる。一方の JavaScript オブジェクトでは参照渡しが行われるので、関数がオブジェクト パラメータを変更すると、その変更が呼び出し側にも見えてしまう。
構造体の性質を簡単に真似るには、割り当てやパラメータ渡し時に JavaScript オブジェクトのコピーを作ればよい。一般的に、ネイティブ言語で構造体を利用する場合、オーバーヘッドはほとんど発生しない。ところが JavaScript でオブジェクトを作成すると大きな負荷が生ずるため、確保するオブジェクトを最小限に抑えるよう慎重になる必要があった。特に割り当てに関しては、新しいオブジェクト インスタンスを丸ごと作成するのではなく、可能な限り各プロパティをコピーするようにした。
もう1つの例は、Objective-C の持つオブジェクト指向という特性だ。JavaScript は、従来のオブジェクト ベースの継承の代わりにプロトタイプ継承(Prototype プロパティ ベースの継承)を提供する。これはかなり簡略化されたオブジェクト継承であり、Objective-C のような従来のオブジェクト指向言語とはあまり互換性がない。幸いにも、JavaScript 用にオブジェクト指向プログラミング(OOP)スタイルのコードを書くのを支援するクラス ライブラリが各種あるので、われわれは(jQuery で有名な)John Ressig 氏によって書かれた
かなりシンプルなものを活用した(最新版 JavaScript の仕様である ECMAScript5 でもクラスは多少サポートされているが、われわれが ECMAScript5 に慣れていなかったことと、タイトな開発スケジュールを考慮し、今回の移植では使用しなかった)。
Objective-C から JavaScript への移植に加え、グラフィックス コードを OpenGL から HTML5 Canvas API に移植する必要もあった。全体的にこれは非常にスムーズにいった。Canvas は驚くほど高速なレンダリング API を備え、API がハードウェア アクセラレーションに対応する Web ブラウザ(IE9 など)ではそれが顕著だった。
Canvas API によりエイリアス処理した線でロープを描画
驚いたことに、モバイル版 Cut the Rope で使用した OpenGL ES よりも Canvas の方が高い性能を示す場面にいくつも遭遇した。その一例が、アンチエイリアス処理された線の描画だ。OpenGL でアンチエイリアス処理された線を描画するには、線をモザイク処理して三角形に分け、端の不透明度を完全に透明化する必要がある。これに対し、HTML5 の canvas は、ライン API で描かれた線を自動的にアンチエイリアス処理してくれる。そのため、われわれは OpenGL バージョンからコードを削除する必要があった。OpenGL コードから一連の三角形の頂点処理を取り除くことで、三角形ストリップ手法で線を描く処理が、オリジナル版でコピーするより格段に優れたパフォーマンスとなった。
結局、およそ1万5,000行のコードが Web ブラウザで実行されることになった(減らしてあるので、お手元の Web ブラウザでソースコードを見ると1万5,000行よりかなり少なく見える)。これだけのコードだと複雑になるだろうと予想した Denis Morozov 氏(ZeptoLab の開発担当ディレクタ)は、早い段階で「HTML5 はこのゲームに必要なスピードとパフォーマンスを実現できるのだろうか」というもっともな疑問を投げかけてきた。
この疑問に回答すべく、われわれは初期の「パフォーマンス」マイルストーンを設定し、ゲームの動作が最も厳しい部分を最小限の形で動かせるよう開発に集中した。具体的には、ロープの表示と複雑な物理シミュレーション エンジンを Web ブラウザ内で動かせるかどうか、という程度の実装だった。