Phaser 3 - линейная интерполяция спрайтов с использованием очереди движения - PullRequest
0 голосов
/ 10 ноября 2018

В настоящее время я использую Phaser 3 для представления состояния моего сервера.

Каждый раз, когда мне отправляется игровое состояние сервера, клиент выглядит так:

var t1 = Date.now();
var serverUpdateDelta = 0;
Client.socket.on('usersPool', usersPool => {
  // usersPool is an object containing all the user data of sockets connected on the server. Looks something like this:
  /*
    usersPool = {
      "user1234": { x: 0, y: 0, direction: "right", moving: true },
      "testuser": { x: 200, y: 250, direction: "down", moving: false }
    }
  */
  // keeping count of milliseconds between updates (usually around 500m)
  serverUpdateDelta = Date.now() - t1;

  // for every user connected on the server...
  for(id in usersPool) {
    let data = usersPool[id]; // this is the user's data

    if(/* the player exists as a sprite in the game...*/) {
      // THIS IS WHERE THE MAGIC SHOULD HAPPEN
    } else {
      genSprite(player);
    }
  }
});

Данные игрока содержат movementQueue, который является просто массивом координат, в которых был пользователь. Это может выглядеть примерно так:

[
  { x: 0, y: 0, direction: 'down', moving: false },
  { x: 5, y: 0, direction: 'right', moving: true },
  { x: 6, y: 0, direction: 'right', moving: false }
]

Это рассчитывается на сервере, но каждый movementStack (элемент в движенииQueue`) генерируется каждые 25 миллисекунд или около того на сервере.

Теперь при получении этого движенияQueue задание заключается в интерполяции значений и соответствующем перемещении спрайта ...

Попытка 1

Сначала я попытался создать функцию, которая будет интерполировать после получения обновления, например:

// THIS IS WHERE THE MAGIC SHOULD HAPPEN

// user's state on the client is set to an interpolated version of the one on the server
player.movementQueue = buffer(data.movementQueue);

Буфер просто сгенерирует интерполированный массив на основе serverUpdateDelta и game.loop.actualFps

затем в функции Game.update я запустил следующее:

for(id in spawnedPlayers) {
  // this will remove the first movementStack from the queue and returns in
  movementStack = spawnedPlayers[id].movementQueue.shift();
  // we then take this movementStack and update the user to that position (and play the walking animation)
  spawnedPlayers[id].update(movementStack);
}

Таким образом, при каждом игровом цикле мы удаляем стек из очереди и устанавливаем для него пользователя.

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

player.movementQueue = player.movementQueue.concat(buffer(data.movementQueue));

Но затем произошло нечто странное, когда игровой цикл не успевал за ходом Queue и игрок двигался очень медленно ...

Попытка 2

Затем я попытался использовать анимацию, которую было бы легко реализовать, просто запустив:

// THIS IS WHERE THE MAGIC SHOULD HAPPEN
_this.tweens.timeline({
    targets: player.sprite,
    tweens: data.movementQueue, // [{x, y}, {x, y}, {x, y}]
    duration: serverDeltaTime/movementQueue.length, // duration between each tween in ms
  });

Это сработало ПОЧТИ отлично, за исключением одной маленькой детали:

Раньше мы запускали метод для игрока на каждом стоке движения: player.update(movementStack), этот метод принимал бы направление пользователя и соответственно анимировал спрайт. Теперь у нас нет возможности сделать это ...

SO

Какие методы или приемы я могу использовать? Чего мне не хватает? Что я мог реализовать? Я спрашиваю об этом, потому что я застрял в этой точке.

Заранее благодарю за помощь.

...