Позиции игрока на стороне сервера или на стороне клиента?

Я только что сделал многопользовательскую браузерную реализацию игры Pong, используя socket.io, и у меня есть вопрос относительно логистики в реальном времени. По сути, ракетка игрока — это просто цветной div, который перемещается вверх или вниз в зависимости от того, какую кнопку он нажимает. При тестировании моей программы на двух разных компьютерах с использованием AWS я заметил, что движение было почти идеально синхронизировано, но иногда не точно. Для игрока, который управляет ракеткой, движение ракетки выполняется локально, но для человека, против которого он играет, сервер постоянно отправляет ему данные о том, двигался ли его противник вверх или вниз.

Мой вопрос: должен ли я выполнять все движения на стороне сервера? Например, пользователь нажимает, чтобы подняться, и он отправляет серверу запрос, который отправляет обоим игрокам, что весло должно двигаться, или мой способ, когда движение вашего весла выполняется локально нормально?

Мой код сейчас выглядит так:

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

paddleMove = 0; // Keep track of which direction to move
speed = 5; 
    if (paddleL.position().top > arena.position().top){ // If left paddle not at top
        if (keysPressed.up) paddleMove -= speed;
    }
    if (paddleL.position().top+paddleL.height() < arena.position().top + arena.height() - 15){ // If left paddle not at bottom
        if (keysPressed.down) paddleMove += speed;
    }
    paddleL.css({  // Move paddle locally
        top: paddleL.cssNumber('top') + paddleMove + 'px'
    });
    socket.emit("moveReq", paddleMove); // Send to server 

Приведенный выше код находится в интервале, который выполняется каждую долю секунды.

Тогда серверная часть выглядит так:

socket.on('moveReq', function(data){   // Send to opponent that other paddle moved
    socket.broadcast.emit("movePaddle", data);
});

Что, в свою очередь, предупреждает другую часть пользовательского кода о перемещении другой ракетки:

socket.on("movePaddle", function(data){

        var paddleMove = 0;
        paddleMove += data; // Data is speed (direction) of movement
        paddleR.css({ // Move right paddle
            top: paddleR.cssNumber('top') + paddleMove + 'px'
        });

Как я уже сказал, движение сейчас довольно хорошее, но не идеальное. Должен ли я не делать никаких движений локальными и делать все это на сервере?


person MarksCode    schedule 21.03.2016    source источник
comment
Имо, вы должны делать движения на стороне клиента и синхронизироваться со стороной сервера в определенное время, в этом случае, когда мяч касается весла, так вы предотвратите перегрузку сервера и предотвратите взлом.   -  person Henri Cavalcante    schedule 22.03.2016


Ответы (2)


В настоящее время я даже работаю над многопользовательской игрой с использованием веб-сокетов. Если вам нужна позиция игрока в реальном времени, это потребует большой пропускной способности.

До сих пор мы занимались прогнозированием и лерпингом. Предположим, есть два связанных игрока с именами A и B.

Допустим, игрок A по умолчанию находится на x=0 (t=0) , поэтому на B он также будет на x=0. Теперь мы начнем излучать x-позицию A каждую 1 секунду (в зависимости от вашей игры, если fps, уменьшите значение)

Через 1 секунду (t=1) точка A находится на x=2 (2 пикселя, по вашему мнению). B получает позицию A через 1,2 секунды (учитывая задержку из-за проблем с сетью). Теперь нам нужно определить положение от x=0 до x=1, предсказав время. (Это все может быть достигнуто с помощью сценариев)

Основная формула (это будет сделано в функции обновления) :

CurrentXposition = (NewXPosition - CurrentXPosition) * deltatime ;

Что ж, вам обязательно нужно поработать над приведенной выше формулой. Дельта-время будет рассчитываться каждый раз, когда мы получаем новую позицию. Итак, здесь мы лерпируем и предсказываем все в одном, используя дельта-время.

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

Подробнее см. в этом блоге,

И это для формулы lerping

person Atik M.    schedule 22.03.2016
comment
Спасибо за это. У меня есть некоторые проблемы, хотя. Я отправляю NewXPosition каждые 250 мс или около того, но при интерполяции символ прыгает, если хотите, всякий раз, когда NewXPosition обновляется. Должен ли я отправлять новое значение lerping с той же скоростью, что и игровые fps? - person NiCk Newman; 08.06.2016
comment
Вы можете обрабатывать синхронизацию положения двумя способами. Один из них — отправить позицию 10 кадров в секунду или нажать клавишу . Вы должны вычислить deltaTime, когда вы получаете каждый кадр, используя метку времени. то есть время, прошедшее с предыдущего кадра, разница между частотами обновления вашей игры, а также вы должны использовать некоторую логику для lerping для имитации физики. - person Atik M.; 10.06.2016

Обновите позицию сразу на стороне клиента. Затем отправьте сообщение о движении на сервер. Когда вы получите сообщение с сервера, синхронизируйте позицию со значением сервера.

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

person Kable    schedule 22.03.2016