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.

因此,我建议您通读上述文章。我很乐意在评论中添加一些我们所做的参考:

这是一个包含已回答问题的庞大主题,因此最好为您指明需要寻找的方向,而不是再次解释。希望对你有帮助。