Update 6:Оптимизация перехода/движения Гладкость для 2D флеш игры
Fenomenas предложил мне, чтобы воссоздать все как можно проще. У меня были сомнения, что это будет иметь какое-то значение, поскольку алгоритм остается прежним, и производительность, похоже, не была проблемой. Во всяком случае, это было единственное предложение, которое я получил, так вот оно:
- 30 FPS: http://www.feedpostal.com/test/simple/30/SimpleMovement.html
- 40 FPS: http://www.feedpostal.com/test/simple/40/SimpleMovement.html
- 60 FPS: http://www.feedpostal.com/test/simple/60/SimpleMovement.html
- 100 FPS: http://www.feedpostal.com/test/simple/100/SimpleMovement.html
Код:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.utils.getTimer;
[SWF(width="800", height="600", frameRate="40", backgroundColor="#000000")]
public class SimpleMovement extends Sprite
{
private static const TURNING_SPEED:uint = 180;
private static const MOVEMENT_SPEED:uint = 400;
private static const RADIAN_DIVIDE:Number = Math.PI/180;
private var playerObject:Sprite;
private var shipContainer:Sprite;
private var moving:Boolean = false;
private var turningMode:uint = 0;
private var movementTimestamp:Number = getTimer();
private var turningTimestamp:Number = movementTimestamp;
public function SimpleMovement()
{
//step 1: create player object
playerObject = new Sprite();
playerObject.graphics.lineStyle(1, 0x000000);
playerObject.graphics.beginFill(0x6D7B8D);
playerObject.graphics.drawRect(0, 0, 25, 50);
//make it rotate around the center
playerObject.x = 0 - playerObject.width/2;
playerObject.y = 0 - playerObject.height/2;
shipContainer = new Sprite();
shipContainer.addChild(playerObject);
shipContainer.x = 100;
shipContainer.y = 100;
shipContainer.rotation = 180;
addChild(shipContainer);
//step 2: install keyboard hook when stage is ready
addEventListener(Event.ADDED_TO_STAGE, stageReady, false, 0, true);
//step 3: install rendering update poll
addEventListener(Event.ENTER_FRAME, updatePoller, false, 0, true);
}
private function updatePoller(event:Event):void
{
var newTime:Number = getTimer();
//turning
if (turningMode != 0)
{
var turningDeltaTime:Number = newTime - turningTimestamp;
turningTimestamp = newTime;
var rotation:Number = TURNING_SPEED * turningDeltaTime/1000;
if (turningMode == 1) shipContainer.rotation -= rotation;
else shipContainer.rotation += rotation;
}
//movement
if (moving)
{
var movementDeltaTime:Number = newTime - movementTimestamp;
movementTimestamp = newTime;
var distance:Number = MOVEMENT_SPEED * movementDeltaTime/1000;
var rAngle:Number = shipContainer.rotation * RADIAN_DIVIDE; //convert degrees to radian
shipContainer.x += distance * Math.sin(rAngle);
shipContainer.y -= distance * Math.cos(rAngle);
}
}
private function stageReady(event:Event):void
{
//install keyboard hook
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown, false, 0, true);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp, false, 0, true);
}
private final function keyDown(event:KeyboardEvent):void
{
if ((event.keyCode == 87) && (!moving)) //87 = W
{
movementTimestamp = getTimer();
moving = true;
}
if ((event.keyCode == 65) && (turningMode != 1)) //65 = A
{
turningTimestamp = getTimer();
turningMode = 1;
}
else if ((event.keyCode == 68) && (turningMode != 2)) //68 = D
{
turningTimestamp = getTimer();
turningMode = 2;
}
}
private final function keyUp(event:KeyboardEvent):void
{
if ((event.keyCode == 87) && (moving)) moving = false; //87 = W
if (((event.keyCode == 65) || (event.keyCode == 68)) && (turningMode != 0)) turningMode = 0; //65 = A, 68 = D
}
}
}
Результаты были такими, как я ожидал. Абсолютно никакого улучшения. Я очень надеюсь, что у кого-то есть другое предложение, поскольку эта вещь нуждается в исправлении. Кроме того, я сомневаюсь, что это моя система, поскольку у меня довольно хороший (8 ГБ оперативной памяти, Q9550 QuadCore intel, ATI Radeon 4870 512MB). Кроме того, у всех остальных, кого я спрашивал, была такая же проблема с моим клиентом.
Обновление 5: еще один пример гладкой флеш-игры, чтобы продемонстрировать, что мое движение определенно отличается от других! См http://www.spel.nl/game/bumpercraft.html
Обновление 4: Я проследили время до рендеринга (Event.RENDER) и сразу после рендеринга (Event.ENTER_FRAME), результаты:
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 24 ms
rendering took: 18 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 232 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
диапазон составляет 12-16 мс. Во время этих различий уже началось шокирующее/деформирующее/мерцающее движение. Существует также 1 пик 232 мс, в то время был относительно большой деформация. Это, однако, не самая большая проблема, самой большой проблемой являются непрерывные мелкие перекосы во время нормального движения. Означает ли это, что кто-нибудь подскажет?
Update 3: После тестирования, я знаю, что следующие факторы не причина моя проблема:
- качества растрового изображения -> не изменились с фотошопом более уродливых 8 цветов оптимизированной графики, никаких улучшений в все.
- Постоянное вращение изображения при повороте -> оно было отключено, никаких улучшений на всех
- Browser рендеринга -> пытался использовать флэш-плеер автономно, без улучшения на всех
Я на 100% уверен, что проблема заключается либо в моем коде, либо в моем алгоритме. Пожалуйста, помогите мне. Прошло почти две недели (1 неделя, когда я задал этот вопрос на SO), и мне еще нужно получить золотой ответ.
Обновление 1: см. Нижнюю часть для полного источника проекта flex и демонстрационную демонстрацию, демонстрирующую мою проблему.
Я работаю над 2d флеш-игрой.корабли игрока создается как объект:
ships[id] = new GameShip();
Когда информация движение и вращение доступно, это направляется на соответствующий корабль:
ships[id].setMovementMode(1); //move forward
Теперь, в рамках этого движения объекта GameShip работает с помощью " Event.ENTER_FRAME»событие:
addEventListener(Event.ENTER_FRAME, movementHandler);
следующая функция затем бежится:
private final function movementHandler(event:Event):void
{
var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
var distance:Number = (newTimeStamp - movementTimeStamp)/1000 * movementSpeed; //speed = x pixels forward every 1 second
movementTimeStamp = newTimeStamp; //update old timeStamp
var diagonalChange:Array = getDiagonalChange(movementAngle, distance); //the diagonal position update based on angle and distance
charX += diagonalChange[0];
charY += diagonalChange[1];
if (shipContainer)
{ //when the container is ready to be worked with
shipContainer.x = charX;
shipContainer.y = charY;
}
}
private final function getDiagonalChange(angle:Number, distance:Number):Array
{
var rAngle:Number = angle * Math.PI/180; //convert degrees to radian
return [Math.sin(rAngle) * distance, (Math.cos(rAngle) * distance) * -1];
}
Когда объект больше не перемещается, прослушиватель событий будет удален. Тот же метод используется для вращения. Все работает почти идеально.
Я установил целевой FPS проекта на 100 и создал счетчик FPS. Согласно счетчику FPS, средний FPS в firefox составляет около 100, а вершина - 1000, а нижняя - 22. Я думаю, что нижняя и верхняя FPS происходят только во время инициализации клиента (запуск).
Проблема в том, что корабль выглядит почти совершенно гладким, в то время как это должно быть просто без «почти» части. Это похоже на то, что корабль «мерцает» очень быстро, вы не можете его увидеть, но трудно сосредоточиться на объекте, пока он движется глазами. Кроме того, время от времени, кажется, есть некоторый штырь частоты кадров, как будто клиент пропускает пару кадров, и вы видите, что он быстро деформируется.
Очень сложно объяснить, какова настоящая проблема, но в целом это то, что движение не является совершенно гладким. Итак, есть ли у вас какие-либо предложения о том, как сделать движение или переход объектов совершенно гладким?
Update 1:
Я воссоздал клиента, чтобы продемонстрировать мою проблему. Пожалуйста, проверьте это.
Клиент:http://feedpostal.com/test/MovementTest.html
Actionscript Project (полный источник):http://feedpostal.com/test/MovementTest.rar
Пример гладкой флеш игры (не созданных мной):
Мне потребовалось довольно много времени, чтобы воссоздать эту версию на стороне клиента, я надеюсь, что это поможет решить проблему.
Обратите внимание: да, на самом деле это довольно гладко. Но это определенно не достаточно гладко.
Что должно выглядеть UtilLib.getTimeStamp()? Это может быть проблема с вашим временем. – grapefrukt
он выполняет следующие действия: var now: Date = new Date(); return now.getTime(); – Tom
Я все еще думаю, что вы слишком зацикливаетесь на этой частоте кадров, и для твердых 30 кадров в секунду будет более реалистично. Однако вы можете попробовать заменить материал Date с помощью getTimer(). Я не уверен, как они сравнивают точность, но я уверен, что это будет быстрее. – grapefrukt