
Framework: Fps
Есть свободная минутка, как раз чтобы рассказать про небольшой, но очень полезный, для моего фреймворка, утилитный класс.
(Утилитными классами я называю классы, которые реализуют только статические методы.)
Frame Per Second — кадры в секунду. данный класс нужен для того, чтобы знать, сколько времени прошло за кадр (delta) и сколько кадров обрабатывается в секунду (fps). Все обновление объектов в фреймворке у меня привязано к секундам. Движение, анимация. Практически любой объект реализует метод update, который принимает в качестве параметра delta — время в секундах, пройденное с прошлой обработки кадра.
Используется этот класс следующим образом.
(Утилитными классами я называю классы, которые реализуют только статические методы.)
Fps
elmortem.core.FpsFrame Per Second — кадры в секунду. данный класс нужен для того, чтобы знать, сколько времени прошло за кадр (delta) и сколько кадров обрабатывается в секунду (fps). Все обновление объектов в фреймворке у меня привязано к секундам. Движение, анимация. Практически любой объект реализует метод update, который принимает в качестве параметра delta — время в секундах, пройденное с прошлой обработки кадра.
package elmortem.core {
import flash.utils.getTimer;
public class Fps {
static private var last_time:int = 0;
static private var last_fps_time:int = 0;
// delta
static public var delta:Number = 0;
// fps
static private var _fps:int = 0;
static private var fps_num:int = 0;
static public function start():void {
last_time = last_fps_time = getTimer();
delta = 0;
_fps = 0;
fps_num = 0;
}
static public function step():void {
// delta
delta = (getTimer() - last_time) / 1000;
last_time = getTimer();
fps_num++;
if(last_time - last_fps_time >= 1000) {
_fps = fps_num;
fps_num = 0;
last_fps_time = last_time;
}
}
static public function get fps():int {
return _fps;
}
}
}
Используется этот класс следующим образом.
public class Gameplay extends State {
private var ball:Ball;
public function Gameplay(attrIn:Object = null) {
super(attrIn);
}
override protected function init():void {
addChild(ball = new Ball());
addEventListener(Event.ENTER_FRAME, onFrame);
Fps.start(); // начинаем считать
}
override public function free():void {
removeChild(ball);
ball = null;
}
private function onFrame(e:Event):void {
Fps.step(); // считаем
trace("fps: "+Fps.fps+", delta: "+Fps.delta);
ball.x += 100 * Fps.delta; // скорость по x - 100 пикселей в секунду
ball.y += 70 * Fps.delta; // скорость по y - 70 пикселей в секунду
}
}
- +3
- elmortem
Комментарии (20)
Я к тому, что ограничение fps если и делать, то не в этом классе. Тут должны быть чистые данные. Если на моём примере смотреть, то ограничение можно сделать в методе onFrame стейта Gameplay.
И каков бы ни был FPS, все будет менятся на заданный шаг по фреймрейту.
По мне так очень надежно и просто к тому же.
Всегда использовал глобальное дельта от фреймрейта.
И никогда не испытывал дискомфорта или хотя бы намеков на него от того, что у меня что-то там не влияет на перемещение. :)
Как ты уже сказал выше, если оно тормозит — то играть в любом случае невозможо, а если все пучком, то все равно что у тебя:
класс или глобальная перменная — играть одинаково комфортно. :)
По моему вешать обработку (игровой update) на Event.ENTER_FRAME не очень хорошо.
А во флеше разве есть другие варианты, кроме того или иного события? Делать обновление реже 30 раз в секунду бессмысленно, задолбаешься синхронизировать отрисовку и обновление — отсюда дрожание, рывки.
Вместо вешать обновление на Event.ENTER_FRAME и нагружать флешку в момент отрисовки (флеш плееру там хватает чего считать и без нашего апдейта) мы вешаем его на таймер TimerEvent.TIMER.
А тайсеры вешать по несколько секунд на Timer так вообще невозможно.
Если работа с чатсицами, то они даже отрисоваться не успевают, как уже уничтожаются.
Timer хорош, например, чтобы пинги слать на сервер, но для всего остального я лично, закрыл ему дорогу.
Но если ваша игра тормозит то она тормозит и на ENTER_FRAME.
Если делать зависимость от дельты (разницы во времени между обновлениями) то тут всеравно к какому событию привязываться, просто при ENTER_FRAME идет отрисовка.
А проблемы с частицами у вас были скорей всего из за неправильного применения.
Проблемы с частицами были из-за того что таймера, потому что как только повесил все на Enter_Frame — все сразу стало корректно работать.
Вот в том то идело. Если игра тормозит, то она тормозит и на Enter_Frame.
Сколько вешал все апдейты на Enter_Frame — все всегда рабтало «ок» (и как-то тормозов из-за скрипта и даже работы бокс2Д не наблюдалось).
Но как только пытался сделать по «человечески» и повесить апдейт на Timer, то сразу проявлялась какая-то рассинхронизация.
Конечно может я глупый и что-то не так делал, но лично мой опыт показал, что Enter_Frame стабильней и надежней.
Если у нас стоит frameRate 60 это не означает что нам нужно провести все нужные расчеты 60 раз за секунду.
Да конечно есть момент проседания когда интрервал таймера меньше интервалов ENTER_FRAME, но визуально мы не заметим этого (в разумных приделах).
Неоднократно сталкивался с ситуациями когда перенос расчетов из ENTER_FRAME спасал ситуацию, и взял для себя за правило использовать таймер.
И зачем ставить frameRate 60? 30 вполне достаточно.