Лучшие практики: ENTER_FRAME vs. Timer - PullRequest
0 голосов
/ 17 сентября 2009

Я создаю Flash-игру, основанную на старом Pacman, и я не уверен, что это лучший способ управлять анимацией.

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

Это, однако, создает проблему необходимости иметь конкретную частоту кадров, и ее изменение позже не может быть и речи, не говоря уже об ограничении очень небольшим количеством различных «скоростей» (см. Ниже). Примером может быть то, что спрайт должен переместиться на 12 пикселей, прежде чем будет определено следующее движение. Если скорость составляет 4 пикселя на кадр, математика довольно проста:

[...]
public var stepCount:uint = 0;

[...]

function enterFrameHandler(e:Event):void
{
    if(stepCount==0) {
    //Some code to evaluate next move. Let's say it evaluates to MOVE RIGHT
    }

    if(MOVE_RIGHT)
    {
        x += 4;
    }

    stepCount++;
    if(stepCount > 2)
    {
        stepCount = 0; //Now ready to evaluate direction again.
    }
}

Это все работает нормально, но, скажем, я хочу, чтобы спрайт перемещался по 5 пикселей на кадр. Тогда количество кадров до следующей оценки не будет вычислено. StepSize должен быть кратным 12, что ограничивает различные возможные скорости (1,2,3,4 и 6 пикселей на кадр).

Именно поэтому я попытался вместо этого основать движение на таймере, который мне также удалось заставить работать, но движение было несколько странным, и казалось, что таймер использует гораздо больше памяти, чем событие ENTER_FRAME. Вместо ровного движения Таймер заставил спрайт замедлиться, ускорить и снова замедлить.

Другим возможным решением может быть класс Tween, но он кажется экстравагантным.

Кто-нибудь имеет опыт работы с тем, что лучше всего работает в других играх?

Мортен Тельманн

Ответы [ 2 ]

6 голосов
/ 18 сентября 2009

У вас есть несколько отдельных вопросов здесь. Ваш первый вопрос: выполнять игровой цикл в кадре или в таймере? Ответ прост - вы должны сделать это в рамочном событии. Причина в том, что независимо от того, как вы перемещаете своих персонажей, экран обновляется ровно один раз за кадр. Таким образом, каждый раз, когда вы вызываете свой игровой цикл более одного раза за кадр, вы тратите процессор, а каждый раз, когда вы вызываете его менее одного раза за кадр, вы жертвуете визуальным качеством. Так что это легко, не беспокойтесь о событиях таймера.

Следующий вопрос заключается в том, должно ли движение вашей игры быть привязано к кадрам или миллисекундам, и ответ заключается в том, что это зависит от игры. Задайте себе вопрос: предположим, что какой-то пользователь играет в вашу игру, и его космический корабль (или что-то еще) летит с заданной скоростью. Внезапно антивирусный пакет пользователя делает что-то тяжелое, и скачок процессора заставляет Flash перестать обновляться на одну секунду. После того, как всплеск закончился, хотите ли вы, чтобы космический корабль продолжал двигаться от того места, где он был, когда начался всплеск? Или вы хотите, чтобы он прыгнул вперёд туда, где он был бы, если бы продолжал двигаться во время шипа? Если вы хотите первое, вы должны привязать свое движение к кадрам; если вы хотите последнее, вы должны привязать его к миллисекундам. Но какой из них лучше, зависит от того, как вы хотите, чтобы ваша игра работала.

Последний вопрос: как именно вы должны перемещать персонажей в своей игре? Исходя из того, что вы написали, я бы сделал это следующим образом. Для основанного на кадре движения (то есть первый подход, описанный ранее):

// the ship moves 25 pixels per second
var shipSpeed:Number = 25;

// the number of seconds per frame, based on the published framerate
var frameTime:Number = 1 / stage.frameRate;

// game loop called each frame:
function gameLoop() { 
    // ...
    playerShip.x += shipSpeed * frameTime;
    // ....
}

Таким образом, движение корабля на экране постоянно, независимо от того, на какой частоте вы публикуете свой SWF. Использование более высокой частоты кадров просто делает движение более плавным. Аналогично, чтобы связать ваше движение со временем, а не с кадрами, просто измените «frameTime» в приведенном выше коде, чтобы оно указывало на время, прошедшее с предыдущего кадра, как описано в ответе Аллана.

1 голос
/ 18 сентября 2009

Да частота кадров будет варьироваться в зависимости от процессора среди других вещей. Поэтому вы должны принять это во внимание в вашем игровом цикле. Мне нравится получать разницу во времени между текущим и старым кадрами и использовать это значение в моих вычислениях. Таким образом, если случится задержка, большее значение разницы будет компенсировано тем фактом, что будет выполнено меньше кадров.

    var _previousTime:Number;

    //gameLoop is the function called on ENTER_FRAME
    public function gameLoop(e:Event):void
    {

      var currentTime:Number = getTimer();
      var difference:Number = currentTime - _previousTime;
      _previousTime = currentTime;

      //use difference variable with calculations involving movement

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...