ビットマップキャッシュ

適切な場合、複雑なベクターコンテンツには、ビットマップキャッシュ機能を使用してください。

ビットマップキャッシュ機能を使用することで、有効な最適化を実行できます。この機能は、ベクターオブジェクトをキャッシュし、内部ビットマップとして表現して、そのビットマップをレンダリングに使用します。この機能を使用することで、レンダリングのパフォーマンスが大幅に向上します。ただし、大量のメモリを消費する可能性があります。ビットマップキャッシュ機能は、複雑なベクターコンテンツ(複雑なグラデーションやテキストなど)に使用します。

複雑なベクターグラフィック(テキスト、グラデーションなど)を含むアニメーション化されたオブジェクトのビットマップキャッシュを有効にすると、パフォーマンスが向上します。ただし、タイムライン再生が含まれるムービークリップなどの表示オブジェクトでビットマップキャッシュを有効にすると、逆効果になります。ランタイムが、キャッシュされたビットマップをフレームごとに更新し、オンスクリーンで再描画しなければならないので、多くの CPU サイクルが必要になります。ビットマップキャッシュ機能が役立つのは、キャッシュされたビットマップを 1 回生成でき、更新の必要がなくそのビットマップを使用する場合のみです。

Sprite オブジェクトに対してビットマップキャッシュを有効にすると、キャッシュされたビットマップをランタイムが再生成することなく、オブジェクトを移動できるようになります。オブジェクトの x プロパティおよび y プロパティを変更しても、再生成は行われません。ただし、その回転、拡大 / 縮小またはアルファ値の変更を試みると、ランタイムはキャッシュされたビットマップを再生成し、その結果、パフォーマンスに影響があります。

注意: AIR および Packager for iPhone で利用できる DisplayObject.cacheAsBitmapMatrix プロパティには、この制限はありません。cacheAsBitmapMatrix プロパティを使用すると、ビットマップの再生成をトリガーすることなく、表示オブジェクトの回転、拡大 / 縮小、傾斜、回転、アルファ値の変更が行えます。

キャッシュされたビットマップは、通常のムービークリップインスタンスよりも多くのメモリを使用します。例えば、ステージ上のムービークリップが 250 x 250 ピクセルの場合、キャッシュされると約 250 KB(キャッシュされない場合は 1 KB)を使用します。

次の例では、りんごのイメージが含まれている Sprite オブジェクトを操作します。次のクラスは、りんごのシンボルにアタッチされます。

package org.bytearray.bitmap 
{     
    import flash.display.Sprite; 
    import flash.events.Event; 
     
    public class Apple extends Sprite 
    { 
        private var destinationX:Number; 
        private var destinationY:Number; 
         
        public function Apple () 
        { 
            addEventListener(Event.ADDED_TO_STAGE,activation); 
            addEventListener(Event.REMOVED_FROM_STAGE,deactivation);     
        } 
         
        private function activation(e:Event):void  
        { 
            initPos();     
            addEventListener (Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function deactivation(e:Event):void  
        { 
            removeEventListener(Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function initPos():void 
        { 
            destinationX = Math.random()*(stage.stageWidth - (width>>1)); 
            destinationY = Math.random()*(stage.stageHeight - (height>>1)); 
        } 
         
        private function handleMovement(e:Event):void  
        { 
            x -= (x - destinationX)*.5; 
            y -= (y - destinationY)*.5; 
             
            if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
                initPos(); 
        } 
    } 
}

りんごにはタイムラインが必要ないので、このコードでは MovieClip クラスの代わりに Sprite クラスを使用します。パフォーマンスを最大にするには、最も軽量のオブジェクトを使用します。次に、以下に示すコードでクラスをインスタンス化します。

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(MouseEvent.CLICK,createApples); 
stage.addEventListener(KeyboardEvent.KEY_DOWN,cacheApples); 
 
const MAX_NUM:int = 100; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
function createApples(e:MouseEvent):void 
{ 
    for (var i:int = 0; i< MAX_NUM; i++) 
    { 
        apple = new Apple(); 
         
        holder.addChild(apple); 
    } 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holder.numChildren; 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holder.getChildAt (i) as Apple; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

ユーザーがマウスをクリックしたときに、キャッシュせずにりんごが作成されます。ユーザーが C キー(キーコード 67)を押すと、りんごのベクターがビットマップとしてキャッシュされ、画面に表示されます。CPU 速度が遅い場合は、この手法によって、デスクトップとモバイルデバイスの両方でレンダリングパフォーマンスが大幅に向上します。

ただし、ビットマップキャッシュ機能を使用することによりレンダリングパフォーマンスが向上しても、メモリ消費量が急激に増加する場合があります。オブジェクトがキャッシュされるとすぐに、オブジェクトのサーフェスが透明なビットマップとしてキャプチャされ、メモリに格納されます。次の図を参照してください。

メモリに格納されたオブジェクトとそのサーフェスのビットマップ

Flash Player 10.1 および AIR 2.5 は、フィルターおよびビットマップの動的アンロードに説明されているのと同じ手法を使用することにより、メモリの使用を最適化します。キャッシュされた表示オブジェクトが非表示またはオフスクリーンの場合、メモリ内のビットマップは、しばらく使用されないと解放されます。

注意: 表示オブジェクトの opaqueBackground プロパティが特定の色に設定されていると、ランタイムは不透明な表示オブジェクトと見なします。ランタイムは、cacheAsBitmap プロパティと共に使用すると、メモリ内に不透明な 32 ビットのビットマップを作成します。アルファチャンネルは 0xFF に設定されます。これにより、ビットマップを画面上に描画する際、透明度が必要ないので、パフォーマンスが向上します。アルファブレンディングを使用しないと、レンダリングがさらに高速化されます。現在の画面深度が 16 ビットに制限されている場合、メモリ内のビットマップは 16 ビットイメージとして格納されます。opaqueBackground プロパティを使用しても、ビットマップキャッシュは暗黙的にアクティブにはなりません。

メモリを節約するには、cacheAsBitmap プロパティを使用して、コンテナではなく各表示オブジェクト上でこのプロパティを有効にします。コンテナ上でビットマップキャッシュを有効にすると、メモリ内で最終ビットマップのサイズが大幅に増大し、211 x 279 ピクセルの 透明なビットマップが作成されます。このイメージは、約 229 KB のメモリを使用します。

フルサイズのグラフィックを表示
コンテナ上でのビットマップキャッシュの有効化

さらに、コンテナをキャッシュすることで、りんごがフレーム上で移動し始めたときに、ビットマップ全体がメモリ内で更新されるリスクがあります。個々のインスタンス上でビットマップキャッシュを有効にすると、7 KB のサーフェスがメモリ内に 6 個キャッシュされます。つまり、42 KB のメモリしか使用されません。

フルサイズのグラフィックを表示
インスタンス上でのビットマップキャッシュの有効化

表示リストから各りんごのインスタンスにアクセスして、getChildAt() メソッドを呼び出すと、Vector オブジェクトに参照が格納され、アクセスが容易になります。

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, cacheApples); 
 
const MAX_NUM:int = 200; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
var holderVector:Vector.<Apple> = new Vector.<Apple>(MAX_NUM, true); 
 
for (var i:int = 0; i< MAX_NUM; i++) 
{ 
    apple = new Apple(); 
     
    holder.addChild(apple); 
     
    holderVector[i] = apple; 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holderVector.length 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holderVector[i]; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

キャッシュされたコンテンツが各フレームで回転、拡大 / 縮小または変更されない場合、ビットマップキャッシュによりレンダリングが改善します。ただし、x 軸および y 軸上の移動以外の変形があると、レンダリングは改善されません。この場合、Flash Player は、表示オブジェクト上で変形が発生するたびに、キャッシュされたビットマップのコピーを更新します。キャッシュされたコピーを更新することにより、CPU 使用率が増加し、パフォーマンスが低下して、バッテリが消耗します。この場合も、AIR または Packager for iPhone の cacheAsBitmapMatrix プロパティにはこの制限がありません。

次のコードでは、移動メソッドのアルファ値を変更して、各フレーム上のりんごの不透明度を変更します。

private function handleMovement(e:Event):void  
{ 
        alpha = Math.random(); 
        x -= (x - destinationX)*.5; 
        y -= (y - destinationY)*.5; 
             
        if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
            initPos(); 
}

ビットマップキャッシュを使用すると、パフォーマンスが低下する原因となります。ランタイムは、アルファ値が変更されるたびに、メモリ内のキャッシュされたビットマップを更新します。

フィルターは、キャッシュされたムービークリップの再生ヘッドが移動するたびに更新されるビットマップに依存します。したがって、フィルターを使用すると自動的に cacheAsBitmap プロパティが true に設定されます。次の図は、アニメーション化されたムービークリップを示しています。

アニメーション化されたムービークリップ

パフォーマンスの問題が発生する可能性があるので、アニメーションコンテンツではフィルターを使用しないようにします。次の図には、デザイナーによってドロップシャドウフィルターが追加されています。

アニメーション化されたムービークリップ(ドロップシャドウフィルター付き)

その結果、ムービークリップ内のタイムラインが再生中の場合、ビットマップは再生成される必要があります。単純な x 変形または y 変形以外の方法でコンテンツが変更される場合も、ビットマップは再生成される必要があります。ランタイムは各フレームでビットマップを再描画します。これにより、多くの CPU リソースが必要になり、パフォーマンスが低下して、バッテリが消耗します。

以下のトレーニングビデオでは、Paul Trani が Flash Professional と ActionScript を使用して、ビットマップを使用したグラフィックを最適化する例を示しています。