2

簡単に言うと、私はリアルタイムのマルチプレイヤー ゲームに取り組んでいます。私のゲームでは、クライアントは更新された位置と速度のデータを 20 Hz の頻度でサーバーに送信します。以下のコード例では、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

ここに問題があります。オブジェクトは非常にぎくしゃくしています。パケットを受信するたびに、他のプレイヤーは少し前または少し後ろにワープするため、遅延補正がオフになっているようで、補間がオフになっているようです。おそらく、誰かが私のコードの明らかな欠陥を指摘したり、プロセスがどのように機能するかについての私の理解を指摘したりできますか?

4

1 に答える 1

2

スムーズなアニメーションのために、サーバー側の位置の更新は、位置/速度ベクトルに保存されている現在の値を使用して固定クロックで行われる必要があります。

クライアントの更新を受信したら、次のティックのために 2 つの計算を行う必要があります。

  • まず、クライアントのベクトルを使用して、プレーヤーが次のティックでとるべき位置を見つけます。
  • 次に、サーバー側プレーヤーがその位置に到達するための新しいベクトルを計算し、その値を使用してサーバー速度を更新します。

サーバーは、次のティックで非常に均一な方法ですべてのクライアントの位置を更新します。2 つ以上のティックを将来に投影するだけで、方向の変化をさらに滑らかにすることができます。遅延を補正しようとするときの目標は、実際には、許容誤差範囲内に収まるようにすることです。

于 2015-02-04T05:48:54.947 に答える