多人游戏运动同步 [英] Multiplayer game movement synchronization

查看:100
本文介绍了多人游戏运动同步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在进行多人游戏,我遇到了同步玩家的问题。

I'm working on a multiplayer game and i'm having problem with synchronizing players.

当玩家按下其中一个移动键时(W,A, S,D)然后客户端发送一个关于按下按钮的数据包,服务器根据按下的键设置速度,并将新速度发送回所有附近的玩家。

When a player presses one of the move keys (W,A,S,D) then the client sends a packet about the pressed button, the server sets the velocity according to the pressed key and sends back to all nearby players the new velocity.

当玩家释放密钥然后客户端发送数据包时,服务器将玩家速度设置为0,0并将位置和速度发送给所有附近的玩家。

When the player release the key then the clients sends a packet, server sets the player velocity to 0,0 and sends the position and velocity to all nearby players.

所以问题是当我释放钥匙时,大多数时候玩家会跳回来。

So the problem is when i release the key, then most of the time the player jumps back.

我怎么能解决这个问题?

How could i fix this?

我正在使用socket.io。

i'm using socket.io.

客户端:

   socket.on('positionEntity', function (data) {
        console.log((data.x - entities[data.id].x)+" "+(data.y - entities[data.id].y));
        entities[data.id].setPosition(data);
    });

    $(document).keyup(function(e) {
        if (e.keyCode == 87) {
            keys.W = false;
            socket.emit("stopMove", {dir: 0, time: Date.now()});
        }

        if (e.keyCode == 65) {
            keys.A = false;
            socket.emit("stopMove", {dir: 1, time: Date.now()});
        }

        if (e.keyCode == 83) {
            keys.S = false;
            socket.emit("stopMove", {dir: 2, time: Date.now()});
        }

        if (e.keyCode == 68) {
            keys.D = false;
            socket.emit("stopMove", {dir: 3, time: Date.now()});
        }
    });

    $(document).keydown(function(e) {
        if (e.keyCode == 87 && !keys.W) {
            keys.W = true;
            socket.emit("startMove", {dir: 0, time: Date.now()});
        }

        if (e.keyCode == 65 && !keys.A) {
            keys.A = true;
            socket.emit("startMove", {dir: 1, time: Date.now()});
        }

        if (e.keyCode == 83 && !keys.S) {
            keys.S = true;
            socket.emit("startMove", {dir: 2, time: Date.now()});
        }

        if (e.keyCode == 68 && !keys.D) {
            keys.D = true;
            socket.emit("startMove", {dir: 3, time: Date.now()});
        }
    });

服务器端:

socket.on('startMove', function(data) {
    if (data.dir == 0) socket.player.setMotionY(-5);
    if (data.dir == 1) socket.player.setMotionX(-5);    
    if (data.dir == 2) socket.player.setMotionY(5);
    if (data.dir == 3) socket.player.setMotionX(5);

    io.sockets.emit("positionEntity", socket.player.serializePosition());
});

socket.on('stopMove', function(dir) {
    socket.player.setMotionX(0);
    socket.player.setMotionY(0);

    io.sockets.emit("positionEntity", socket.player.serializePosition());
});


推荐答案

这是一项非常复杂的任务,你正在努力我作为宠物项目的一部分做过的事情;)

This is a very complex task you are working on and something I've done as part of a pet project ;)

你正在开发一个客户端 - 服务器架构游戏,所以服务器是游戏逻辑和决策的最终权威。他们目前处理渲染的方式会因延迟而使速度和方向发生突然变化(正如您所注意到的那样!)

You're working on a client-server architecture game so the server is final authority on game logic and decisions. They way you are currently handling rendering will make sudden changes in velocity and direction apparent due to latency (as you have noticed!)

诀窍是缓冲远程的移动信息玩家让你总是稍微延迟渲染玩家。我在项目中保持原始状态,只使用位置数据,而不是加速度或速度。例如,当玩家A在他的机器上移动时,命令不会立即被发送以接收确认,他移动并在我的网络发送循环的下一个滴答中(每秒10个滴答),他的位置被激发到更新所有客户端的服务器。附近有这个新职位。这些客户端为每个远程播放器都有一个缓冲区,它在呈现更新之前将每个位置存储一段时间(100毫秒)。通过这种方式,客户端会稍微延迟渲染,但我可以在每个位置坐标之间进行插值(平滑精灵/模型的过渡),以实现平滑运动和速度与加速度的幻觉。

The trick is to buffer movement information of remote players so you always render player with a slight delay. I kept things primitive in my project and used only positional data, not acceleration or velocity. Example, when player A moves on his machine a command is not instantly sent to receive acknowledgement, he moves and on the next tick of my networking send loop (10 ticks per second) his position is fired to the server who updates all clients in the vicinity with this new position. These clients have a buffer for each "remote" player which stores each position for a time (100 milliseconds) before rendering the update. In this way the client is rendered with a slight delay but I can interpolate (smooth the transition of the sprite/model) between each positional co-ordinate to achieve smooth motion with the illusion of velocity and acceleration.

客户端代码的BASIC插值函数。该系统最多只为每个远程播放器排队两个更新,其中更新阵列中的索引0是两个中的较旧者。所以索引0可能是远程玩家位置0ms而索引1是远程玩家位置100ms。

A BASIC interpolation function for client code. This system only queued two updates for each remote player at most, where index 0 in the update array was the older of two. So index 0 might be the remote player position 0ms and index 1 is the remote player position at 100ms.

interpolate: function() {
  var timeDifference = new Date().getTime() - this.serverUpdates[1].time;
  // Percentage of time passed since update was received (I use 100ms gaps)
  var interPercent = (timeDifference) / 100;

  // Latest updates (index 1 is the newest state)
  var s1 = this.serverUpdates[0],
    s2 = this.serverUpdates[1];

  // Need to lerp between values provided in latest update and older one
  var p = (new Vector3(s2.position)).subtract(new Vector3(s1.position));
  p = p.timesScalar(interPercent);

  // New position is the older lerped toward newer position where lerp 
  //percentage is the time passed 
  this.position = new Vector3(s1.position).add(p);

  // Now update rotation in a smooth manner
  var rotationDifference = (s2.rotation - s1.rotation);
  if (rotationDifference && rotationDifference != 0) {
    this.rotation = s1.rotation + (rotationDifference * interPercent);
  }
},

在该代码中,我收到的更新大约是相隔100ms,所以在时间0位置是s1,时间100ms s2是位置。因此,如果我们收到s2后已经过了50ms,则实体在两个位置之间的比例为50%。这对我的需要很好,但在其他类型的游戏中可能无法解决或者可能需要调整。

In that code I was receiving updates that were approx 100ms apart, so at time 0 position is s1 and time 100ms s2 is the position. So if 50ms have passed since we received s2 then the entity is 50% between the two positions. This was fine for my need but may not work out in other types of games or might need tweaking.

这些资源是解释网络游戏和处理延迟的良好开端,你会惊讶于实现插值和推断对你的游戏在远程客户端的平滑性的差异。

These resources are an excellent start to explain networked games and dealing with latency, you'll be amazed at the difference implementing interpolation and extrapolation will have on your game smoothness in remote clients.

http://gafferongames.com/networking-for-game-programmers/什么 - 每个程序员需要知道的游戏网络/

https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization < - 真的很棒!

https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization <- REALLY GOOD!

https://developer.valvesoftware.com/wiki/Lag_compensation

祝你好运:)

这篇关于多人游戏运动同步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆