Upd: На Adobe Сookbooks появился пример более аккуратного таймера, использующего другой подход для пресечения задержек. Я собираюсь им воспользоваться и всем рекомендую(хотя бы ознакомиться стоит). На данный момент там нет скачиваемого класса, но автор обещал выложить нормально написанный пример.
Flex cookbook entry: Accurate Timer class.
Во Flash player’е работа встроенного таймера зависит от проигрывания flash ролика. Такая зависимость приводит к большим погрешностям и не делает поправку при дальнейшем выполнении. Это достаточно известная тема и уже много раз об этом писали.
К примеру, класс приложения для подсчёта погрешностей в ролике с частотой в 24 кадра:
package{ import flash.display.Sprite; import flash.events.TimerEvent; import flash.utils.Timer; import flash.utils.getTimer; [SWF(frameRate="24")] public class TestTimer extends Sprite{ protected var _started:int; public function TestTimer():void{ super(); const timer:Timer = new Timer(1000); timer.addEventListener(TimerEvent.TIMER, timerHandler); _started = getTimer(); timer.start(); } protected function timerHandler(event:TimerEvent):void{ const count:int = (event.target as Timer).currentCount; trace(count, (getTimer()-_started-1000*count)*0.001); } } }
При выполнении, покажет, что уже до конца минуты таймер пропустит одну итерацию.
27 0.79
28 0.79
29 0.791
30 0.833
31 0.835
32 0.875
33 0.918
34 0.9580000000000001
35 0.966
36 1
37 1.002
38 1.042
39 1.083
Я немного расширил класс и добавил автоматическую поправку, а так же подсчёт пропущенных итераций. Если изменить код, чтоб опробовать новый класс
package{ import aw.events.AccurateTimerEvent; import aw.utils.AccurateTimer; import flash.display.Sprite; import flash.events.TimerEvent; import flash.utils.Timer; import flash.utils.getTimer; [SWF(frameRate="24")] public class TestTimer extends Sprite{ protected var _started:int; public function TestTimer():void{ super(); const timer:Timer = new AccurateTimer(1000); timer.addEventListener(TimerEvent.TIMER, timerHandler); _started = getTimer(); timer.start(); } protected function timerHandler(event:AccurateTimerEvent):void{ const count:int = (event.target as Timer).currentCount; trace(count, (getTimer()-_started-1000*count)*0.001); } } }
То можно убедиться, что такого нарастающего отставания больше нет. Оно, конечно, осталось, но в самой минимальной величине.
27 0.027
28 0.025
29 0.026000000000000002
30 0.025
31 0.027
32 0.027
33 0.025
34 0.025
35 0.025
36 0.027
37 0.026000000000000002
38 0.025
39 0.027
Класс AccurateTimer расширяет flash.utils.Timer и добавляет в него методы pause()/resume() для останова текущей итерации(я понимаю,что это сомнительный функционал, но надо было идти до конца
) и свойство missedIterations, которое содержит общее количество пропущенных итераций. Так же, с этим классом идёт своё событие AccurateTimerEvent, которое расширяет событие оригинального таймера и добавляет свойство missedIterations, которое содержит количество пропущенных итераций за время завершённой итерации(если она выполнялась в два раза дольше и более).
Скачать aw.utils.AccurateTimer (42)
Метки: flash.utils.Timer, Timer
почему бы просто не делать поправку на каждый тик, таким образом получим саморегулирующийся таймер
var count:int = timer.currentCount;
var diff:int = getTimer() – started – 1000*count;
trace(count, diff * .001);
timer.delay = 1000 – diff;
вот результаты:
1 0.039
2 0.039
3 0.05
4 0.039
5 0
6 0.001
7 0.039
8 0.039
9 0.039
10 0
11 0.039
12 0.04
13 0
14 0
15 0.039
16 0
17 0
18 0.039
19 0.039
20 0
21 0
22 0
23 0.039
24 0.039
25 0
ps чтобы оставить коммент нужно региться, это немножко жестоко во времена openid
Именно это и происходит внутри AcсurateTimer, он саморегулируется.
Регистрироваться надо всего один раз, жаль one-face умер.
Всегда не хватало pause и resume в таймере!)
А, кстати… поставил плагин openid