C 实时多人游戏延迟补偿

C 实时多人游戏延迟补偿,c,lua,udp,enet,C,Lua,Udp,Enet,简而言之,我正在开发一款实时多人游戏。在我的游戏中,客户端以20Hz的频率向服务器发送更新的位置和速度数据。在下面的示例代码中,我使用LuaJIT FFI将Lua表中的数据转换为C结构。这是一种通过网络传输数据的好方法: self.dt_f = self.dt_f + dt if self.dt_f >= self.tick_f and self.id then self.dt_f = self.dt_f - self.tick_f local player = self

简而言之,我正在开发一款实时多人游戏。在我的游戏中,客户端以20Hz的频率向服务器发送更新的位置和速度数据。在下面的示例代码中,我使用LuaJIT FFI将Lua表中的数据转换为C结构。这是一种通过网络传输数据的好方法:

self.dt_f = self.dt_f + dt
if self.dt_f >= self.tick_f and self.id then
    self.dt_f = self.dt_f - self.tick_f

    local player = self.players[self.id]
    local data   = {
        type          = packets["player_update_f"],
        id            = self.id,
        position_x    = player.position.x,
        position_y    = player.position.y,
        position_z    = player.position.z,
        velocity_x    = player.velocity.x,
        velocity_y    = player.velocity.y,
        velocity_z    = player.velocity.z,
    }

    local struct = cdata:set_struct("player_update_f", data)
    local encoded = cdata:encode(struct)
    self.client:send(encoded)
end
当服务器接收到数据包时,它会尝试调整数据以补偿特定客户端与自身之间的延迟:

local player        = self.players[id]
player.position     = update.position     or player.position
player.velocity     = update.velocity     or player.velocity

local server = self.server.connection.socket
local peer   = server:get_peer(id)
local ping   = peer:round_trip_time() / 2 / 1000

player.position = player.position + player.velocity * ping
数据规范化后,它将更新后的位置信息广播给所有其他客户端:

local data = {
    type          = packets["player_update_f"],
    id            = id,
    position_x    = player.position.x,
    position_y    = player.position.y,
    position_z    = player.position.z,
    velocity_x    = player.velocity.x,
    velocity_y    = player.velocity.y,
    velocity_z    = player.velocity.z,
}
local struct  = cdata:set_struct("player_update_f", data)
local encoded = cdata:encode(struct)
self.server:send(encoded)
当其他客户端最终获得数据包时,它们会根据与服务器的延迟调整数据:

if id ~= self.id then
    self.players[id]          = self.players[id] or {}
    self.players[id].position = update.position  or self.players[id].position
    self.players[id].velocity = update.velocity  or self.players[id].velocity

    local ping = self.client.connection.peer:round_trip_time() / 2 / 1000
    self.players[id].position = self.players[id].position + self.players[id].velocity * ping
end

问题就在这里:对象非常不稳定。每次我收到一个数据包时,其他玩家都会向前或向后移动一点,所以我的延迟补偿似乎关闭了,这使得插值功能关闭。也许有人会指出我的代码中的一些明显缺陷,或者我对该过程如何工作的理解?

对于平滑动画,服务器端位置更新应该在固定时钟上使用为位置/速度向量存储的当前值进行

收到客户端更新后,您需要为下一个勾号进行两次计算:

  • 首先,使用客户的向量,找到玩家在下一个滴答声中应该处于的位置
  • 接下来,计算服务器端玩家到达该位置的新向量,并使用该值更新服务器速度
然后,服务器将在下一个时间点以非常统一的方式更新所有客户端位置。只需向未来投射2个或更多的记号,即可进一步平滑方向更改。当试图补偿延迟时,目标实际上只是在可接受的误差范围内