0

for ループを使用せずに何かを何度も実行するのに問題があります。これを見てください:

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite {

        public function Main() {

            addEventListener("done", caller);

            caller();            

        }

        public function caller(e:Event = null):void {

            trace("hello!");

            dispatchEvent(new Event("done"));

        }

    }

}

これを歌うと、「エラー #2094: イベント ディスパッチの再帰オーバーフロー」が発生します。本当に速い。イベント ディスパッチャと caller() が内部で呼び出され、エラーが発生するまでネストされていることがわかります。

私がやりたいことはこれです:「caller()が完了したら、もう一度呼び出します」ではなく、「終了する前にcaller()を呼び出します」

ここで、タイマーを使用して所要時間を推測したり、ENTER_FRAME を使用したりすることを人々が提案し始める前に、この caller() にはグラフィック データがなく、スプライトに接続されず、完了するまでにかかる時間は、コールトゥコール。完全に終了してから実行する方法を本当に探しています。

ご協力いただきありがとうございます。


ご回答ありがとうございます。タイマーを使用しましたが、呼び出しが多すぎてタイマー間隔が短すぎてオーバーフローする可能性がありました。だから私は単純化して、イベントベースのforループクラスを作成しようとしました(forループのように動作するクラスですが、すべてのリソースを飲み込むのを避けるためのイベントがあります)解決策は、関数を呼び出し、完了時にタイマーを呼び出すことでした。タイマーの完了時に関数を再度呼び出し、それらを互いに跳ね返します。基本的:

call function
wait
call function
wait etc.

タイマーが 0 に設定されていて、すべての関数が呼び出されるまで swf がフリーズしたとしても、関数は再び実行される前に完了します。

やってみて:

package {

import flash.display.Sprite;

public class Efl extends Sprite { // the main class

    public function Efl() {

        // make four functions...
        function init (o:Object):void { // akin to the first part of the for loop

            o.value = 0;

        }

        function condition(o:Object):Boolean { // like the condition portion of the for loop

            if (o.value <= 100) {

                return (true);

            } else {

                return (false);

            }

        }

        function next(o:Object):void { // the increment part of a for loop

            o.value++;

        }

        function statements(o:Object):void { // the body of the for loop

            trace(o.value);

        }

        // put the four functions in one new EventForLoop
        var test1:EventForLoop = new EventForLoop(init, condition, next, statements, 1); // delay is 1 ms
        test1.start(); // set it into motion

        // do it again all in one line - not pretty but it works
        var test2:EventForLoop = new EventForLoop(
            function (o:Object):void { o.value = 0; },
            function (o:Object):Boolean { if (o.value <= 50) return (true); else return (false); },
            function (o:Object):void { o.value++ },
            function (o:Object):void { trace("> " + o.value) },
            20); // delay in 100ms

        test2.start(); // start it up

        // if you try this out, the two will run intertwined since the delays are different.

    }

} 
}

ループを実行するクラスは次のとおりです。

package {

import flash.events.EventDispatcher;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;

public class EventForLoop extends EventDispatcher {

    // functions to call when simulating the for loop
    private var initializer:Function; // is run once at the start of the loop
    private var condition:Function; // returns boolean to tell the loop to continue or not
    private var step:Function; // the function that runs after the loop is complete
    private var statements:Function; // the actual body of the loop

    private var timeout:Timer; // the timer to avaoid overflows

    private var operator:Object = new Object(); // this is an object to hold and pass values across all the sub loop functions. it is the parameter passed to all four functions

    // some event constants
    static const NEXT:String = new String("EFLNext"); 
    static const DONE:String = new String("EFLDone");


    // constructor just loads vars and sets up timer
    public function EventForLoop (init:Function, cond:Function, stepper:Function, stat:Function, delay:Number = 0) {

        initializer = init;
        condition = cond;
        step = stepper;
        statements = stat;

        timeout = new Timer(delay, 1);

    }

    // the mail loop function...
    private function next(e:Event = null):void {

        // Try this and the lone afte the loop:
        // trace ("start statements");

        if (condition.call(null, operator)) { // if the condition is still true...

            statements.call(null, operator); // do the body statements of the loop
            step.call(null, operator); // increment
            dispatchEvent(new Event(EventForLoop.NEXT)); // dispatch the event so that thw wait can start

        } else { // condition returns false??

            dispatchEvent(new Event(EventForLoop.DONE)); // tell the event dispatcher the loop is done
            removeEventListener(EventForLoop.NEXT, wait); // stop event listeners
            timeout.removeEventListener(TimerEvent.TIMER_COMPLETE, next); 

        }

        // trace ("finish statements\n");
        // this line and the one before the if() will show that the functcion ends before starting again, even if the Timer wait 0ms

    }

    // very simple function that waits and ten triggers the  loop again
    private function wait(e:Event):void {

        timeout.reset();
        timeout.start();

    }

    // metod used to set the loop running
    public function start():void {

        initializer.call(null, operator); // use the initioalizer to set the operator Object
        addEventListener(EventForLoop.NEXT, wait); // when the loops done, wait
        timeout.addEventListener(TimerEvent.TIMER_COMPLETE, next); // when done waiting, loop again

        next(); //do the first loop

    }

} 

}
4

6 に答える 6

1

他の回答者と同様の質問があります。どのくらいの頻度で電話をかけますか? 呼び出しが終了したらすぐに繰り返すことが必要な場合は、プログラムの他の部分が実行される機会がありません。

于 2009-07-25T22:54:27.630 に答える
1

を試してみるとよいでしょうflash.utils.setTimeout()。の一番下に置きcaller()、タイムアウトを設定します。非常に短いタイムアウト間隔を指定すると、次に Flash が機会を得たときに非同期的に再帰します。

あるいは、ENTER_FRAME イベントはほぼ同じことを行います (非常に高いフレームレートを除く)。Flash は、1 つのフレームのすべての処理ロジックが完了するまで、次のフレームのレンダリングを遅らせます。さらに、Flash はシングルスレッドであるため、関数の 2 つのコピーが同時に実行されることはありません。

于 2009-07-25T17:27:52.763 に答える
0

OK、あなたが言ったことを知っています

彼のcaller()はグラフィックデータを持たず、Spriteに接続されません

私はそれが完全に終わった後にだけそれを実行する方法を本当に探しています。

だから私はそれらに対処し、それからエンターフレームが最良の解決策であることをあなたに伝えます:)

エンターフレームイベントリスナーを使用するために、グラフィック表現やステージへのアクセスは必要ありません。あなたは単に次のことをすることができます:

var s:Shape = new Shape();
s.addEventListener(Event.ENTER_FRAME, caller)

private function caller():void
{
    //do stuff
}

上記では、フレーム入力イベントをリッスンするシェイプを作成するだけで、それだけに使用できます。

2番目の部分については、コードが実行時に解釈され、関数(この場合は呼び出し元)に到達すると、終了するまで別の関数またはその関数の外部のコード行を実行しません。したがって、前の呼び出しが終了するまで、二度と実行されないことがわかります。

したがって、エンターフレーム(またはタイマー)が最善/唯一のソリューションです。

于 2009-07-25T16:50:34.323 に答える
0

これは課題ですか?

forループが必要ない場合は、whileループはどうでしょうか。

タイマーを使おうとするとうまくいくかもしれませんが、面倒になります。どうしてもタイマーを使用する必要がある場合、関数がまだ実行されている場合は、ブールフラグをtrue/falseに設定してください。タイマーイベントは、関数が終了したかどうかを確認します。終了した場合は、もう一度呼び出します。

于 2009-07-25T06:37:17.817 に答える
0

あなたがしたいのは、 Caller() が終了したときに新しいイベントをディスパッチし、それから caller を再度呼び出すことです。

ただし、最大ループカウンターが必要です。そうしないと、スタックオーバーフローエラーが発生します。

イベント リスナーへの弱い参照を使用することを忘れないでください。常に未使用のオブジェクトを使用してガベージ コレクションを取得し、アプリをよりスムーズかつ高速に実行できるようにします。

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite {

        public function Main() {

            addEventListener("Call_ME_AGAIN", callCaller, false, 0, true );


            caller();            

        }


        private var _counter:int = 0;
        private const LOOP_TIMES:int = 100;
        public function caller(e:Event = null):void {

            trace("hello!");

            if (counter != LOOP_TIMES)
            {
              dispatchEvent(new Event("Call_ME_AGAIN"));
              counter++;
            }
            else if (counter == LOOP_TIMES)
            { //reset the counter so it can happen again when you want
              counter = 0;
             }

        }

        public function callCaller(e:Event = null):void {

            e.stopImmediatePropagation();

            caller(null);

        }

    }

}
于 2009-07-25T17:28:36.740 に答える
0

enterFrame を使用します... Flash はフレーム ベースです... プロセスが終了したら、関数をもう一度呼び出す時間があるかどうかを確認します。ない場合は、次のフレームが来るのを待ちます...

addEventListener("enterFrame", loop);
function loop(e) {
   var maxtime=1000/stage.frameRate;
   var t1=getTimer();
   while(getTimer()-t1 < maxtime) {
      myProcess();
   }
}
于 2009-07-25T12:31:56.973 に答える