多人游戏移动同步

我正在开发一款多人游戏,并且遇到同步玩家的问题。

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

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

所以问题是当我释放键时,大部分时间玩家跳回来。

我怎么能解决这个问题?

我使用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()); }); 

这是一个非常复杂的任务,你正在做的事情,我已经做了一个宠物项目的一部分;)

您正在开发一个客户端 – 服务器架构游戏,因此服务器是游戏逻辑和决策的最终权威。 他们目前正在处理渲染的方式会导致速度和方向的突然变化,由于延迟(因为你已经注意到!)

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

客户端代码的基本插值函数。 这个系统最多只能为每个远程播放器排队两个更新,其中更新数组中的索引0是较早的两个。 所以索引0可能是远程播放器位置0ms,索引1是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); } }, 

在那个代码中,我接收到大约100毫秒的更新,所以在0时间位置是s1,时间100ms s2是位置。 所以如果我们收到s2以后已经过了50ms,那么这个实体在这两个位置之间是50%。 这对我的需求是好的,但可能无法在其他types的游戏中运行,或者可能需要调整。

这些资源是解释networking游戏和处理延迟的一个很好的开始,你会惊奇地发现,在远程客户端实现内插和外推会对游戏的平滑性产生影响。

http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/

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

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

祝你好运 :)