FLASHのパフォーマンスをあげるための10のコツ


ActionScriptでパフォーマンスをあげるためのいくつかのコツです。
純粋なソースでのチューニング方法をあげているTIPSは多いけどそういうのとはちょっと違う切り口のものを。

1.大量のDisplayObjectを同じルールで動かすときには、ひとつずつ指定しないでDisplayObjectContainerでラップしてまとめて移動させる

リストのように表示されているものをまとめて動かす場合にはforなどでまわしてひとつずつ座標を指定していくのではなくて、ひとつ上のレイヤーでDisplayObjectContainerでラップしてそちらを移動しましょう。
個別に動かす必要がある場合にはひとつずつ移動して、まとめて動かす場合にはひとつ上のレイヤーで一気に移動させるように場合によって切り替えることでかなりのパフォーマンスアップが期待できます

var container:MovieClip = new MovieClip();
for( var i:uint = 0 ; i < 1000 ; i++ ){
    var item:MovieClip = new MovieClip();
    item.y = i * 100;
    conteiner.addChild( item );
}


//まとめて動かす.
public function move( y:Number ):void{
    container.y = y;
}

2.レイアウトなどの計算をキャッシュさせる

EnterFrameなど同じような処理をなんども行う場合、途中までおこなった計算を次も使いまわせるものに関しては、
クラスメンバーとして保存しておいて使いまわす方法もあります.
行う処理によっては効果は大きいですが、管理しなければならないものが増えるのでバグも発生しやすくなります.



3.特定の値に対して特定の値を返すものに関しては、計算結果をキャッシュしておく

ID等、特定のある値に対してある固定値を返すものに関しては、結果をキャッシュしておいて2度目意向はキャッシュから取得する方法があります.
渡される値が決まっている場合で、内部で行う処理が重たいものに関してはかなりの効果が期待できます.

public static var _somethingHolder:Array = new Array();
public static function getSomething( id:String ):Number{
    if( _somethingHolder[id] == undefined ){
        //createCache
        _somethingHolder[id] = 何らかのidに紐づく値を計算;
    }
    return _somethingHolder[id];
}

4.visible=falseを使わずに必要ないものはDisplayObjectツリーから外しておく

特に処理の重いTextFieldや、もしくはタイムラインアニメーションをもつMovieClipなどが対象となりますが、
表示したり消したりを繰り返すものでも、visibleで切り替えずにDisplayObjectのツリーから削除しておいたほうがパフォーマンスがいいです。
とくにタイムラインアニメーションをもつものは見えていなくても再描画処理対象になります。
座標など、表示にかかわるプロパティにアクセスする場合DisplayObjectツリーに含まれる数を減らすことでかなりのパフォーマンスのアップが期待できます.

追記:
ものによって、処理が重くならないものもあるみたいです。
DisplayObjectツリーの追加・削除の処理自体重い処理ではあるので、場合によってはvisibleで行ったほうがパフォーマンスあがる場合があります。



5.整形処理などで再計算が必要ないと判断される場合には処理をスキップする.

幅を指定し、それに応じて内部で再整形処理を行う場合などで、同じ幅を指定された場合には再整形の計算はいらないので無駄な計算が行われないように処理をスキップしましょう.

private var _lastWidth:Number;
override public function set width( w:Number):void{
    w = Math.floor( w );
    if( w == _lastWidth ){
        return;//Exit
    }
    _lastWidth = w;
    //色々な処理.
}

6.タイミングを徹底的にずらす

体感的なパフォーマンスアップとして最も効果がある方法のひとつです.
瞬間的にCPU使用率が100%(デュアルコアの場合には50%の場合もあります)になるとコマ落ちが発生してユーザーの体感として、はっきり重いと感じることになります。
大量のループ、大量の整形、大量のインスタンス生成など、処理が多い場合には1フレーム内で行っていた処理を、EnterFraeなどを用いて1フレームあたりの処理量を減らすことができます.

public function create():void{
    for( var i:uint = 0 ; i < 1000 ; i++ ){
        var instance:SomeHeavyClass = new SomeHeavyClass();
    }
}

上記を以下のように変えます

private var _index:uint;
public function create():void{
    _index = 0;
    addEventListener( Event.ENTER_FRAME , _onEnterFrame );
}
public function _onEnterFrame( event:Event ):void{
    var instance:SomeHeavyClass = new SomeHeavyClass();
    i++;
    if( i == 1000 ){
        removeEventListener( Event.ENTER_FRAME , _onEnterFrame );
    }
}

また内容によっては前の方で述べた「レイアウトなどの計算をキャッシュさせる」の項目をあわせて用いることで毎フレーム同じ計算をすることを防ぎます.



7.素材はラスターで

FLASHベクター素材が便利ですが、ベクター素材の表示はかなりのパフォーマンスが必要になります.
とくに表示量が多いばあいには致命的なポイントになってきます.
拡大・縮小や回転などの処理を行わない場合、めんどうでも徹底的にpngなどのラスターの素材を用いるようにしましょう.
ベクター素材の場合にはベクターのポイント数などに気をつけましょう.
※簡単にポイント数を減らす方法に関してはそのうち書きます



8.alphaの使用ををさけられるケースでは避ける

背景が固定色など、透過する必要が無く、素材でなんとかできる場合には素材側でなんとかしましょう.
(アルファを利かせた状態の色の素材を用意するなど)
FLASH側でのアルファ処理はかなりのパフォーマンスを必要とします.



9.EnterFrameやタイマーは必要なくなった時点で確実に破棄を

ある一定位置まで移動するなどの処理など、たいてい時間を用いた処理はあるタイミングで不必要になります.
一定位置に到達した段階など必要なくなった時点で確実にイベントを破棄しましょう.



10.BitMapを用いる

cacheAsBitmapプロパティをうまく用いることで高速化できるケースがかなりあります.
ただし、回転やアルファ、スケールなどの項目に頻繁にアクセスする場合にはそのたびにビットマップキャッシュの処理が発生するので逆に重くなるケースもあります.
回転やアルファ、スケールなどにEnterFrameなどを用いて頻繁にアクセスする場合にはfalse、頻繁にアクセスしなくなった段階でtrueなど状態によって切り替えることで最大限に効果を発揮できます.
場合によってはcacheAsBitmapを用いずに、BitMap.draw()でキャプチャを行いそちらを用いる方法のほうが良い場合もあります.
使う場合には、CPU使用率を眺めながらcacheAsBitmapを使ったほうが良いのか悪いのかを見極める必要があります.




ほかにもいくつかあるけどとりあえずこのへんで.