Время для многопользовательских игр в Node.js - PullRequest
0 голосов
/ 25 мая 2020

Я хотел бы создать простую многопользовательскую игру с Node.js и socket.io. Моя текущая настройка времени не оптимальна, так как рендеринг не плавный. Пока что игроки просто кружатся по холсту.

Я пытаюсь примерно объяснить эту настройку, добавляя несколько фрагментов кода, пожалуйста, дайте мне знать, когда потребуется дополнительный код.

Каждый раз, когда клиент подключается к серверу, новый игрок создается и добавляется в список игроков. Кроме того, мы добавляем слушателей для ключевых вводов клиентов (которые в основном меняют направление).

io.on("connection", (socket) => {
    const p = playerList.add(socket.id);
    socket.on("keydown", (key) => p.addControlKeyDown(key));
    socket.on("keyup", (key) => p.addControlKeyUp(key));
}

Также на стороне сервера, у нас есть обновление l oop. Так как в Node.js нет requestAnimationFrame, я пробовал использовать setInterval. После каждого обновления мы отправляем то, что важно для рисования (это то, для чего предназначена p.extract ()) всем клиентам.

function updateLoop() {
    for (p of playerList.players) {
        p.update();
    }
    const currentPlayers = playerList.players.map((p) => p.extract());
    io.emit("playerUpdate", currentPlayers);
}

const interval = setInterval(updateLoop, 30);

Я уже пробовал здесь 30 миллисекунд, но это не так. Не решает проблему.

На клиенте мы слушаем обновления:

let players = [];

socket.on("playerUpdate", (currentPlayers) => {
    players = currentPlayers;
});

На клиенте у нас также есть отрисовка l oop с использованием requestAnimationFrame:

function drawLoop() {
    clearCanvas();
    players.forEach(drawPlayer);
    requestAnimationFrame(drawLoop);
}

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

example animation

Как это можно улучшить?

Моя первая идея заключалась в том, чтобы избежать l oop на стороне клиента, поскольку мы уже есть на сервере, и напрямую оттуда отправлять запрос на отрисовку клиентам, но это оказывается еще хуже.

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

1 Ответ

1 голос
/ 26 мая 2020

Первая проблема заключается в том, что ваш рендеринг на клиенте связан с ответом от сервера. Другими словами, это сильно зависит от QoS вашей сети, которое в большинстве случаев не очень хорошее. Вы будете получать эти «зависания».

Вы можете избавиться от этого, введя интерполяцию в позицию вашего игрока ( вы были правы в комментариях ).

Примерно сказал, вам нужно «угадать», где другой игрок будет go, пока ответ не дойдет до клиента.

Здесь есть отличное объяснение

С точки зрения клиента этот подход работает так же гладко, как и раньше - прогнозирование на стороне клиента работает независимо от задержки обновления, поэтому очевидно, что он также работает при предсказуемых, хотя и относительно нечастых, обновлениях состояния. Однако, поскольку состояние игры транслируется с низкой частотой (продолжаем пример каждые 100 мс), у клиента очень скудная информация о других объектах, которые могут перемещаться по миру.

Я рекомендую вам прочитать статьи, подобные приведенным выше. Я с удовольствием добавляю несколько ссылок, которые мы также сделали в комментариях:

Это такой огромный топ c с уже отвеченными вопросами, так что лучше дать вам направление того, что вам нужно искать, вместо того, чтобы объяснять это снова. Надеюсь, это вам поможет.

...