Лучший способ выполнить функцию после одного кадра? - PullRequest
2 голосов
/ 23 марта 2009

В ActionScript3 для Flash Player 9+, как лучше всего вызывать «разовую» функцию ровно после одного кадра?

Мне известен класс Timer и его использование, а также метод callLater в Flex UIComponents (который, просматривая исходный код, не выглядит очень эффективным в этом сценарии). Мне также известно о setTimeout (во flash.utils).

Класс Timer и утилита setTimeout основаны на времени, так как мы можем гарантировать, что наша функция будет вызываться ровно после одного кадра?

Из моего ограниченного тестирования кажется, что функции, переданные в setTimeout, выполняются только после хотя бы одного кадра (попробуйте установить задержку равной 0). Но это не гарантировано.

Конечно, мы могли бы прослушивать события Event.ENTER_FRAME из DisplayObject, но это кажется избыточным для однократного отложенного вызова функции.

Ответы [ 5 ]

3 голосов
/ 23 марта 2009

Flex был предназначен для абстрагирования фрейм-плейера от Flash, поэтому вы не найдете много полезного для решения вашей проблемы. Лучший подход - слушать ENTER_FRAME, как вы предлагаете. Если это излишне (и я не уверен, почему вы так думаете), вы можете создать вспомогательный класс, который принимает DisplayObject и Function в качестве аргументов, которые автоматически добавляют / удаляют слушатель события ENTER_FRAME для вас.

public class NextFrameCommand() {

    private var functionToCall : Function;

    public function NextFrameCommand(dObj: DisplayObject, func : Function) {
        functionToCall = func;
    }

    public function start() : void {
        dObj.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }

    private function onEnterFrame(e : Event) : void {
        e.target.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
        functionToCall.call();
    }

}

Я не тестировал этот код, но, надеюсь, вы поняли идею ...

1 голос
/ 23 марта 2009

Играя с решениями, предоставленными Тео и brd6644, я пришел с этим. Это позволяет нескольким функциям (с параметрами) ставиться в очередь и выполняться по порядку в следующем кадре.

public class DelayedFunctionQueue
{
    protected var queue:Array;
    protected var dispatcher:Sprite;

    public function DelayedFunctionQueue()
    {
        queue = new Array();
        dispatcher = new Sprite();
    }

    public function add( func:Function, ... args ):void
    {
        var delegateFn:Function = function():void
        {
            func.apply( null, args );
        }
        queue.push( delegateFn );
        if ( queue.length == 1 )
        {
            dispatcher.addEventListener( Event.ENTER_FRAME, onEF, false, 0, true );
        }
    }

    protected function onEF( event:Event ):void
    {
        dispatcher.removeEventListener( Event.ENTER_FRAME, onEF, false );
        queue = queue.reverse();
        while ( queue.length > 0 )
        {
            var delegateFn:Function = queue.pop();
            delegateFn();
        }
    }
}

Может быть кому-то полезно.

0 голосов
/ 21 октября 2013

ENTER_FRAME не является избыточным - что-то вроде этого короткое и простое

addEventListener(Event.ENTER_FRAME, function(e:Event):void
{
    removeEventListener(Event.ENTER_FRAME, arguments["callee"]);
    onceOffFunction();
}
0 голосов
/ 23 марта 2009
var timerSprite:Sprite = new Sprite();

timerSprite.addEventListener(Event.ENTER_FRAME, oneFrameHandeler);

function oneFrameHandeler(e:Event):void
{
   timerSprite.removeEventListener(Event.ENTER_FRAME, oneFrameHandeler);
   timerSprite = null;

   trace("one frame later!")
}
0 голосов
/ 23 марта 2009

Один из способов - узнать, сколько кадров в секунду установлено для вашего проекта, и разрешить функции setTimeout задержаться на 1 кадр в пределах этого параметра.

Таким образом, если ваш проект настроен на 24 кадра в секунду, вы задерживаетесь на 42 миллисекунда в setTimeout.

...