Node.js 中的多人游戏计时
Timing for multiplayer games in Node.js
我想用 Node.js 和 socket.io 创建一个简单的多人游戏。我当前的计时设置不是最佳的,因为渲染不流畅。到目前为止,玩家只是在 canvas.
上移动的圆圈
我尝试通过添加一些代码片段来粗略地解释此设置,请在需要更多代码时告诉我。
每次客户端连接到服务器时,都会创建一个新玩家并将其添加到玩家列表中。此外,我们为客户的关键输入添加了监听器(这基本上改变了方向)。
io.on("connection", (socket) => {
const p = playerList.add(socket.id);
socket.on("keydown", (key) => p.addControlKeyDown(key));
socket.on("keyup", (key) => p.addControlKeyUp(key));
}
还有服务器端,我们有一个更新循环。由于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;
});
在客户端我们也有使用 requestAnimationFrame
:
的绘制循环
function drawLoop() {
clearCanvas();
players.forEach(drawPlayer);
requestAnimationFrame(drawLoop);
}
服务器和客户端之间的通信正常,但如您所见,时间安排并不是最佳的。
如何改进?
我的第一个想法是避免客户端循环,因为我们已经在服务器上,并从那里直接向客户端发送绘制请求,但结果更糟。
我知道对于复杂的多人游戏,必须在同步方面付出更多的努力,而且还拍摄游戏世界的快照并实际向客户端呈现 "past"。我希望这个简单的例子不需要这么复杂的方法。
第一个问题是您在客户端上的渲染与服务器的响应相结合。换句话说,高度依赖于您的网络的 QoS,这在大多数情况下都不是很好。你会得到那些 "freezes".
您可以通过对玩家的位置进行插值来摆脱这种情况(您在评论中是对的)。
粗略地说,您需要 "take a guess" 知道其他玩家将去哪里,直到响应到达客户端。
有很好的解释here
From the point of view of a client, this approach works as smoothly as before – client-side prediction works independently of the update delay, so it clearly also works under predictable, if relatively infrequent, state updates. However, since the game state is broadcast at a low frequency (continuing with the example, every 100ms), the client has very sparse information about the other entities that may be moving throughout the world.
因此,我建议您通读上述文章。我很乐意在评论中添加一些我们所做的参考:
- Interpolating positions in a multiplayer game
- Dealing with lag in XNA + lidgren
这是一个包含已回答问题的庞大主题,因此最好为您指明需要寻找的方向,而不是再次解释。希望对你有帮助。
我想用 Node.js 和 socket.io 创建一个简单的多人游戏。我当前的计时设置不是最佳的,因为渲染不流畅。到目前为止,玩家只是在 canvas.
上移动的圆圈我尝试通过添加一些代码片段来粗略地解释此设置,请在需要更多代码时告诉我。
每次客户端连接到服务器时,都会创建一个新玩家并将其添加到玩家列表中。此外,我们为客户的关键输入添加了监听器(这基本上改变了方向)。
io.on("connection", (socket) => {
const p = playerList.add(socket.id);
socket.on("keydown", (key) => p.addControlKeyDown(key));
socket.on("keyup", (key) => p.addControlKeyUp(key));
}
还有服务器端,我们有一个更新循环。由于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;
});
在客户端我们也有使用 requestAnimationFrame
:
function drawLoop() {
clearCanvas();
players.forEach(drawPlayer);
requestAnimationFrame(drawLoop);
}
服务器和客户端之间的通信正常,但如您所见,时间安排并不是最佳的。
如何改进?
我的第一个想法是避免客户端循环,因为我们已经在服务器上,并从那里直接向客户端发送绘制请求,但结果更糟。
我知道对于复杂的多人游戏,必须在同步方面付出更多的努力,而且还拍摄游戏世界的快照并实际向客户端呈现 "past"。我希望这个简单的例子不需要这么复杂的方法。
第一个问题是您在客户端上的渲染与服务器的响应相结合。换句话说,高度依赖于您的网络的 QoS,这在大多数情况下都不是很好。你会得到那些 "freezes".
您可以通过对玩家的位置进行插值来摆脱这种情况(您在评论中是对的)。
粗略地说,您需要 "take a guess" 知道其他玩家将去哪里,直到响应到达客户端。
有很好的解释here
From the point of view of a client, this approach works as smoothly as before – client-side prediction works independently of the update delay, so it clearly also works under predictable, if relatively infrequent, state updates. However, since the game state is broadcast at a low frequency (continuing with the example, every 100ms), the client has very sparse information about the other entities that may be moving throughout the world.
因此,我建议您通读上述文章。我很乐意在评论中添加一些我们所做的参考:
- Interpolating positions in a multiplayer game
- Dealing with lag in XNA + lidgren
这是一个包含已回答问题的庞大主题,因此最好为您指明需要寻找的方向,而不是再次解释。希望对你有帮助。