AS3のfl.transitions.Tween、その注意点

AS3のfl.transitions.Tweenが途中で止まるんです。
毎回止まるわけじゃなく、気まぐれに止まるんです。
何が原因かしばらくわからんかった。
再現するサンプルを作ったから、
テレビの前のみんなも一緒に考えてみてくれ。

答えはCMの後で!!


以下のスクリプトは、
ドットを100個生成し、フェードインして表示させるものです。
アニメーションにはfl.transitions.Tweenクラスを使用しています。
Tweenの終了時にイベントを受け取って、トレースしています。
100個のTweenが終了し、100回トレースしてほしいのですが、
かなりの確率で100回トレースされないです。
ただしうまく100回トレースされることもあります。

import fl.transitions.*;
import fl.motion.easing.*;
import flash.utils.*;
stage.frameRate = 30;

//Tween終了カウンタ
var c:int = 0;

//100ミリ秒ごとに一つTwennを生成する。100個まで
var myTimer:Timer = new Timer(100, 100);
myTimer.addEventListener("timer", createTween);
myTimer.start();

function createTween(__e:TimerEvent=null) {

    //Tween目視用スプライトを生成
    var spr:Sprite = new Sprite();
    var shape:Shape = new Shape();
    var gra:Graphics = shape.graphics;
    gra.beginFill(0xff0055);
    gra.drawCircle(0,0,5);
    spr.addChild(shape);
    addChild(spr);
    spr.x = Math.random()*500;
    spr.y = Math.random()*500;

    //Tweenを生成
    var twn:Tween = new Tween(spr, "alpha", Quadratic.easeInOut, 0, 1, 10, true);
    twn.addEventListener(TweenEvent.MOTION_FINISH, onFinish);

}

//Tween終了のイベントハンドラ
function onFinish(__e:TweenEvent):void {
    trace("Finish", ++c);
}

正解は、
「生成したTweenインスタンスが、ガベージコレクトの餌食になっている」
でした。

AS2版のTweenでは、この現象は起こっていませんでした。
Tweenクラスは、内部的にはonEnterFrameイベントを受け取って
トゥイーン処理が行われています。
AS2版のTweenでは、onEnterFrameのリスナであるために、
ガベージコレクトを免れていました。

AS3版のTweenでも、内部的にはevent.ENTER_FRAMEのリスナになっていますが、
リスナに追加される際に「弱い参照」で追加されています。
(今回のことで、addEventListenerするときに「弱い参照」が利用できることを知りました!)
「弱い参照」は通常の参照とは違い、参照カウントが加算されない参照みたいです。

このため、上のコードでは、
Tweenインスタンスを参照するのはfunction内のローカル変数のみであるため、
functionを抜けた後、ガベージコレクトされていたというオチでした。

余談ですが、
フレームレートを上げると、トレースされる数も減るため、
ガベージコレクトのタイミングはフレームレートの影響を受けるみたいですね。

カテゴリー: ActionScript3, AS3fromAS2 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です