【发布时间】:2020-05-25 11:39:15
【问题描述】:
我想用 Node.js 和 socket.io 创建一个简单的多人游戏。我当前的时序设置不是最佳的,因为渲染不流畅。到目前为止,玩家只是在画布上移动的圆圈。
我尝试通过添加一些代码 sn-ps 来大致解释此设置,请在需要更多代码时告诉我。
每次客户端连接到服务器时,都会创建一个新玩家并将其添加到玩家列表中。此外,我们为客户端的关键输入添加了侦听器(这基本上改变了方向)。
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的draw loop:
function drawLoop() {
clearCanvas();
players.forEach(drawPlayer);
requestAnimationFrame(drawLoop);
}
服务器和客户端之间的通信是有效的,但是正如你所看到的,时间并不是最佳的。
如何改进?
我的第一个想法是避免客户端循环,因为我们已经在服务器上,并直接从那里向客户端发送绘图请求,但结果更糟。
我知道,对于复杂的多人游戏,必须在同步方面付出更多努力,而且还需要拍摄游戏世界的快照并将“过去”实际呈现给客户。我希望这个简单的例子不需要这么复杂的方法。
【问题讨论】:
-
似乎只有在服务器返回响应时才能为框架呈现更新,对吧?如果是这样,这绝对是一个错误的想法。您的 FPS 将完全取决于网络质量,这在大多数情况下都不是很好,因此您会“冻结”。
-
我不确定你的意思。绘图循环甚至在没有发送新更新时也可以工作,因为客户端中有全局“玩家”变量。但你是对的,这可能会导致冻结。这可以通过线性插值和“向前看”来解决。但是这个问题不是在gif中可以看到的吧?编辑:好的,也许正是这个!我在考虑更长的冻结时间。
-
恕我直言,你应该看看这个方向来解决这个问题 - gamedev.stackexchange.com/questions/5053/…
-
谢谢。有多个答案。你的意思是马丁的帖子链接在那里吗? stackoverflow.com/questions/3276821/…(“在真正的游戏中你应该做的是在本地位置和远程位置之间进行插值。”)。听起来很有趣!
-
您的问题似乎格式正确,所以我投了赞成票。好像位置插值有帮助,那我写个答案吧?
标签: node.js socket.io html5-canvas multiplayer requestanimationframe