
Честный таймер
На днях у меня возникла резко возникла необходимость в «правильном» таймере для генерации событий. Когда затестировал стандартный Timer на маленьких временных интервалах я пришел в тихий ужас, например, на величине тика 125мс я получил колоссальное расхождение между реальными шагами порядка 30 процентов или около того. И вот я стал думать, а что же мне вообще делать?
В первую очередь нагуглилось вот такое решение но от этого мало что изменилось в лучшую сторону, лаги уменьшились примерно до 10 процентов(проверял через getTimer()). И тут я совершенно случайно наткнулся на один интересный метод Смысл его в следующем: как ни странно но событие Event.SOUND_COMPLETE работает на редкость четко, и если создать пустой звуковой файл нужной длинны (в моем случае 125мс (120bpm)), то можно на его SOUND_COMPLETE в рекурсивном вызове например генерить событие «tick». Вот кусочек моего кода:
Может быть данный способ не совсем верен с этической точки зрения, но главное что он работает.
В комментах плиз предлагайте свои способы, возможно есть решение поизящнее.
p.s. пустой звуковой файл я создал в Adobe Audition Generate->Silence 0.125
В первую очередь нагуглилось вот такое решение но от этого мало что изменилось в лучшую сторону, лаги уменьшились примерно до 10 процентов(проверял через getTimer()). И тут я совершенно случайно наткнулся на один интересный метод Смысл его в следующем: как ни странно но событие Event.SOUND_COMPLETE работает на редкость четко, и если создать пустой звуковой файл нужной длинны (в моем случае 125мс (120bpm)), то можно на его SOUND_COMPLETE в рекурсивном вызове например генерить событие «tick». Вот кусочек моего кода:
private function startTimer(e:MouseEvent):void
{
start_bt.removeEventListener(MouseEvent.CLICK, startTimer);
silentSound = new silence120(); //грузим пустой звук длительностью 125мс из библиотеки
this.timerTick(new Event("timer_start")); // Запускаем таймер
}
private function timerTick(event:Event):void {
this.dispatchEvent(new Event("tick")); // диспатчим тик
channel = silentSound.play();
channel.addEventListener(Event.SOUND_COMPLETE, timerTick); // переподписываемся на событие SOUND_COMPLETE
myFunction();//тут можем также что-нибудь выполнять на каждый тик нашего импровизированного таймера
}
Может быть данный способ не совсем верен с этической точки зрения, но главное что он работает.
В комментах плиз предлагайте свои способы, возможно есть решение поизящнее.
p.s. пустой звуковой файл я создал в Adobe Audition Generate->Silence 0.125
- +5
- MXPain
Комментарии (28)
Я в основном спрайте сцены делаю
, где World — класс мира, в котором разворачиваются все действия игры и который, как и все спрайты игры, наследуются от SpriteEx, который в свою очередь имеет метод update:
В любом месте я перегружаю метод update и получаю значение, сколько времени прошло.
Я бы уж делал как-то так:
t = new time — prevtime;
if (t >= delay)
{
prevtime = new time — (t — delay);
событие();
}
То не в состоянии въехать в оптимизацию с секторным делением большой карты.
То не в состоянии въехать в код с заменой деления более простыми операциями. Второй вариант кода без накопления погрешности, потому что она не сбрасывается, а учитывается за счет вычитания от эталонной величины.
Ты написал говнокод. Если ты даже основу игрового цикла пишешь говнокодом, мне страшно представить, что там у тебя в коде вообще. И это не предобразования Фурье блин, это элементарная математика. Программисты блин. Паттерны идите учите лучше.
И самый ужас — ты не учишся и не в состоянии въехать в простейщий чужой код.
Ну что значит проще? Твой код просто избегает «страшного и ужасного» деления пару десятков раз в секунду. При этом в жертву ты приносишь вот это самое ">". Сам смотри. Вот наступил момент, когда условие выполняется. И наступил этот момент не ровно через delay, а немного позже. И ты это «немного позже» берешь за новую отправную точку. Другими словами с каждым тиком ты ставишь контрольную точку на отметке delay + погрешность. Вот так она и накапливается.
Мой код такой погрешностью не страдает в принципе.
ты видимо код не понял, объясняю на примере
шаг кадра 33 мс, допустим мы выполнили шаг на 30 мс позже. тогда для нового времени берем время на 30мс раньше. т.о. через пару кадров мы выполним его раньше на кадр, благодаря вычитанию. а без вычитания будет отклонения на 0-1 кадров каждый тик
что то, что это не страшное и ужасное, а бесполезная оптимизация, не понятно какое прикладное применение у такого точного таймера, если точность все равно вычисляется с погрешностью <= 30мс
Вот мой код, в котором ее нет:
Из-за чего сыр-бор — трудно поменять единственную строку, чтобы все стало ровнее? Да пишите как знаете, только не доказывайте мне полезность накопительных погрешностей.
У него это либо трололо, дибо воинструющее свойство указанного выше вьючного животного.
Вот тут flashgamedev.ru/viewtopic.php?f=10&t=4916 я пытался обьяснить как сделать отпимизацию за счет посекторного разбиения карты — не понятно было только ему. Выводы сделать можно. Сии комментарии еще одна иллюстрация.
зы: сделал короче комментарий по поводу более оптимального кода.
меняем на
профит!
:)
Если нужен именно таймер, а он часто нужен, то вот что у меня есть:
У всех был такой период, когда мы пытались сделать что-то идеальное, качественное. Когда я учился в школе, тоже писал всякие движки и никому не нужную фигню. Просто задумайтесь над тем, что вы делаете. Можно делать хорошие игры, а можно делать якобы идеальный код, но последнее не будет означать, что ваша игра тоже получится классной. Всем успехов и не ссорьтесь :)
Если на долю секунды происходит подвисание — все таймеры соответственно подвисают тоже.
Самый адекватный вариант это через getTimer(); + делать один на всю игру ENTER_FRAME и в него через Vector.аттачить фунции на обновления.
В таким случае все обновления будут поочередными. Это снизит нагрузку на проц и уменьшит погрешность таймера в разы