Progression FrameworkのForLoopとDoTweenerで、ウッヒョーイエー!ダーイ(Die)!

このエントリをはてなブックマークに追加このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加このエントリをkwoutに追加
2008年4月19日 土曜日1:47:10

そんな訳でProgression Frameworkの話。つか、何で俺だけこんなに沢山の問題にぶち当たるのだろうか?やはり開発スタイル間違ってるのか?
さて今回は、ForLoopコマンドでDoTweener実行しようとしたらスタックオーバーフローで死ぬって話。

■問題と原因

この理由は案外簡単で、実はForLoop使わなくても、多分DoTweener再利用しようとしたら発生すると思う。
原因になってる、DoTweenerのコードはこの部分。

/*======================================================================*//**
* @inheritDoc
* @langversion 3.0
* @playerversion Flash 9.0.45.0
*/
/*=======================================================================*/
protected override function _executeProgress():void {
    // 既存のイベントハンドラメソッドを保存する
    _onCompleteFunction = tweeningParameters.onComplete;//・・・・・・・(1)-1
   
    // イベントハンドラメソッドを登録する
    tweeningParameters.onComplete = _onComplete;//・・・・・・・(1)-2
   
    // アニメーションを開始する
    if ( !Tweener.addTween( _target, _tweeningParameters ) ) {
        // 処理を終了する
        _executeComplete();
    }
}

/*======================================================================*//**
*
* @langversion 3.0
* @playerversion Flash 9.0.45.0
*/
/*=======================================================================*/
private function _onComplete():void {
    // Tweener に設定されていた onComplete() メソッドを実行する
    if ( _onCompleteFunction is Function ) {
        _onCompleteFunction.apply( null );//・・・・・・・(2)
    }
   
    // 処理を終了する
    _executeComplete();
}

(1)と(2)は俺が入れたんだけど、この2箇所のコードがポイント。
処理の流れを追うと、

  1. DoTweenerコマンドが始まると、元々Tweenerに渡す予定だったonComplete関数を_onCompleteFunctionに退避して((1)-1)、
  2. 代わりにDoTweenerの終了処理に入れてる((1)-2)。

こうする事で、Tweenerの処理が終わった後呼ばれるのが、DoTweenerコマンドで定義されてる_onComplete()になる。
で、

  1. DoTweenerの終了処理で、_onComplete関数が呼ばれる。
  2. _onComplete関数の中で元々の終了処理である_onCompleteFunction()を実行する。

でまぁ、DoTweenerの処理は滞りなく終了するわけだけど、ここで大きな異変が。
(1)-2の部分で、Tweener用のパラメータが最初とは違うものになっちゃってる。わけです。
具体的に言うとonComplete。こいつが_onComplete関数になっちゃってるから、次にもう一回このDoTweenerコマンドを使うとどうなるか?
処理の流れを追うと、

  1. DoTweenerコマンドが始まると、元々Tweenerに渡す予定だったonComplete関数を_onCompleteFunctionに退避して((1)-1)、
  2. 代わりにDoTweenerの終了処理に入れてる((1)-2)。
  3. DoTweenerの終了処理で、_onComplete関数が呼ばれる。
  4. _onComplete関数の中で元々の終了処理である_onCompleteFunction()を実行する。
  5. が、2回目の「元々の終了処理」は_onComplete関数であるため、_onComplete関数が実行される。
  6. _onComplete関数の中で元々の終了処理である_onCompleteFunction()を実行する。
  7. _onCompleteFunction関数である、_onComplete関数が実行される。
  8. _onComplete関数の中で元々の終了処理である_onCompleteFunction()を実行する。
  9. _onCompleteFunction関数である、_onComplete関数が実行される。
  10. ・・・

こんな感じで無限に_onComplete()が呼ばれ続け、最終的にはスタックオーバーフローで終了。

■解決策

DoTweener#_onCompleteを以下のように修正。

private function _onComplete():void {
    // Tweener に設定されていた onComplete() メソッドを実行する
    if ( _onCompleteFunction is Function ) {
        _onCompleteFunction.apply( null );
    }

    //onCompleteを元に戻す。
    tweeningParameters.onComplete = _onCompleteFunction;
    _onCompleteFunction = null;
   
    // 処理を終了する
    _executeComplete();
}

要するに、「終了時には元に戻しましょう」ということでいいと思う。でも成功確認しかしてないけど。

トラックバック URL :

コメントをどうぞ

HTML convert time: 0.606 sec.