ActionScript 3.0で始めるオブジェクト指向スクリプティング

第58回 【特別編】ビットマップのキャッシュとオブジェクトの使い回し

この記事を読むのに必要な時間:およそ 8 分

技術評論社より発売された拙著ActionScript 3.0パフォーマンスチューニングから,ActionScript 3.0の最適化の仕方をご紹介する特別編の3回目は,ふたつのお題を採上げる。第1は,アニメーションを滑らかに再生するためのビットマップイメージの扱いだ。そして第2は,オブジェクトを使い回すこと,いわばエコなスクリプティングの勧めである。

アニメーションの重さを測るふたつの物差し

アニメーションが重いとか軽いとかいわれるとき,実はふたつの物差しがある。ひとつはデータの容量だ。そしてもうひとつは,描画するためのCPUの負荷である。

ベクターグラフィックスが軽いといわれるのは,前者の容量を指す。だが,描画についてはディスプレイがピクセルで表示するため,ベクターはビットマップに変換しなければならない(これをラスタライズという)。その処理にCPUが使われる。つまり,ベクターグラフィックスの描画は重くなる図1左図)。

他方,ビットマップグラフィックスは,画像のピクセル数が増えるほどデータ容量は大きくなる。けれど,ディスプレイには,ピクセルのまま映せば済む。したがって,CPUの負荷が少ないので,ビットマップグラフィックスの描画は軽い図1右図)。

ベクターグラフィックス
  • 数学的なデータ→容量は小さい
  • ビットマップに変換(ラスタライズ)して描画→CPU負荷が高い
ビットマップグラフィックス
  • ピクセルごとのデータ→容量は大きい
  • ピクセルをスクリーンに映す→CPU負荷が低い

図1 ベクターグラフィックスとビットマップグラフィックス

図1 ベクターグラフィックスとビットマップグラフィックス 図1 ベクターグラフィックスとビットマップグラフィックス

とくにPCの環境では,ダウンロードするデータの容量より,画面を描き替えるアニメーションの滑らかさが求められる。そうした場合には,グラフィックスをビットマップにすると,データは膨らんでも描画が速められる。もっとも,これはFlashのアニメーションすべてにいえることで,スクリプトにかぎった話ではない。この知識を踏まえて,次項からActionScriptのお題に移る。

平行移動のアニメーションではDisplayObject.cacheAsBitmapプロパティをtrueにする

まずは,上から下に単純にスクロールするインスタンスを大量につくって,アニメーションがどうなるか見てみよう。[ライブラリ]のMovieClipシンボルにクラスを定めて図2),インスタンスは動的につくることにする。

図2 [ライブラリ]のMovieClipシンボルに[クラス]を定める

図2 [ライブラリ]のMovieClipシンボルに[クラス]を定める

図2 [ライブラリ]のMovieClipシンボルに[クラス]を定める

メインタイムラインに書くフレームアクションは,以下のスクリプト1のとおりだ。まず,forループで決められた数(nCount)のMovieClipインスタンス(_mc)をつくってタイムラインのランダムな位置に置き,Vectorオブジェクト(instances)に納める。

つぎに,DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)にリスナー関数(xMove())を加えた。そして,リスナー関数は,VectorオブジェクトからforループでMovieClipインスタンスを順に取出し,下にスクロールさせる。なお,ステージ下端(nStageHeight)を超えたインスタンスは,上端に戻している。

スクリプト1 数多くのインスタンスを上から下にスクロールさせる

// フレームアクション: メインタイムライン
var nStageHeight:int = stage.stageHeight;
var nCount:uint = 500;
var instances:Vector.<MovieClip> = new Vector.<MovieClip>(nCount);
for (var j:uint = 0; j < nCount; j++) {
  var _mc:MovieClip = new MyClass();
  instances[j] = _mc;
  addChild(_mc);
  _mc.x = Math.random() * stage.stageWidth;
  _mc.y = Math.random() * stage.stageHeight;
}
addEventListener(Event.ENTER_FRAME, xMove);
function xMove(eventObject:Event):void {
  for (var i:uint = 0; i < nCount; i++) {
    var instance:MovieClip = instances[i];
    instance.y += 5;
    if (instance.y > nStageHeight) {
      instance.y -= nStageHeight;
    }
  }
}

アニメーションの速さを確かめるので,フレームレートは最高の120FPSに設定しておこう図3)。

図3 フレームレートを120FPSに設定

図3 フレームレートを120FPSに設定

[ムービープレビュー]でアニメーションを見ると,数多くのインスタンスが下に向かってスクロールする図4)。フレームレートに対して明らかに遅いと感じるだろう(処理の速い環境の場合は,インスタンスの数を増やす)。

図4 数多くのインスタンスが下に向かってスクロールする

図4 数多くのインスタンスが下に向かってスクロールする

アニメーションするインスタンスは,フレームごとに描き替えられる。インスタンスがベクターグラフィックスであれば,ラスタライズもそのたびに行われる。しかし,インスタンスを単純に移動するだけなら,つぎのフレームでも同じビットマップがつくられるはずだ。DisplayObject.cacheAsBitmapプロパティtrueにすると,そのビットマップをメモリにとっておいて,つぎのフレームでも使えるときは使い回す。

以下のスクリプト2では,[ライブラリ]のビットマップ(クラスMyClass)からインスタンスをつくるforループの中で,各インスタンスのDisplayObject.cacheAsBitmapプロパティにtrueが設定してある。[ムービープレビュー]を確かめると,アニメーションは明らかに速くなったのがわかるだろう。

スクリプト2 インスタンスDisplayObject.cacheAsBitmapプロパティをtrueに設定する

// フレームアクション: メインタイムライン
var nStageHeight:int = stage.stageHeight;
var nCount:uint = 500;
var instances:Vector.<MovieClip> = new Vector.<MovieClip>(nCount);
for (var j:uint = 0; j < nCount; j++) {
  var _mc:MovieClip = new MyClass();
  instances[j] = _mc;
  addChild(_mc);
  _mc.x = Math.random() * stage.stageWidth;
  _mc.y = Math.random() * stage.stageHeight;
  _mc.cacheAsBitmap = true;
}
addEventListener(Event.ENTER_FRAME, xMove);
function xMove(eventObject:Event):void {
  for (var i:uint = 0; i < nCount; i++) {
    var instance:MovieClip = instances[i];
    instance.y += 5;
    if (instance.y > nStageHeight) {
      instance.y -= nStageHeight;
    }
  }
}

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入