gpt4 book ai didi

javascript - 多人游戏 Action 同步

转载 作者:数据小太阳 更新时间:2023-10-29 05:50:12 26 4
gpt4 key购买 nike

我正在开发一款多人游戏,但我在同步玩家时遇到了问题。

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

当玩家释放按键时,客户端发送一个数据包,服务器将玩家速度设置为 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 在他的机器上移动时,不会立即发送命令以接收确认,他移动并在我的网络发送循环的下一个滴答声中(每秒 10 个滴答声)他的位置被触发到更新所有客户端的服务器这个新位置附近。这些客户端为每个“远程”播放器都有一个缓冲区,在呈现更新之前将每个位置存储一段时间(100 毫秒)。通过这种方式,客户端的渲染会有轻微的延迟,但我可以在每个位置坐标之间进行插值(平滑 Sprite /模型的过渡),以实现具有速度和加速度错觉的平滑运动。

客户端代码的基本插值函数。该系统最多只为每个远程玩家排队两个更新,其中更新数组中的索引 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,时间 100 毫秒是位置 s2。因此,如果自从我们收到 s2 以来已经过去了 50 毫秒,那么实体在两个位置之间为 50%。这很好地满足了我的需要,但可能不适用于其他类型的游戏或可能需要调整。

这些资源是解释网络游戏和处理延迟的良好开端,您会惊讶于实现插值和外插对远程客户端游戏流畅度的影响。

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

祝你好运:)

关于javascript - 多人游戏 Action 同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18114901/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com