エンティティ補間と遅延補償

回線が遅くても敵がカクつかず、自分の狙いどおり弾が当たる。スナップショット補間とサーバー巻き戻しの原理を押さえれば、遅延に強く公平なネットゲームの当たり判定を設計できます。

応用ゲーム開発ネットワーク同期遅延補償スナップショット補間当たり判定マルチプレイヤー最終更新: 2026-07-29
3つの要点
TL;DR
  1. サーバーは一定レートでスナップショットを送り、クライアントは受信済みの過去2点を意図的な遅延(補間バッファ)を挟んで内挿することで、パケットが疎でも他プレイヤーを滑らかに描画する。
  2. ラグ補償はサーバーが撃った瞬間のクライアント時刻に全エンティティを巻き戻し、その過去状態で当たり判定を取る。撃った側は『見えたとおり当たる』が、撃たれた側は遮蔽後に撃たれる不公平が原理的に発生する。
  3. 内挿は過去を描くので低遅延に見えて安全、外挿は未来を予測するので当たるが誤予測で巻き戻る。補間バッファ長・スナップショットレート・巻き戻し上限がプレイ感と公平性のトレードオフを決める。

なぜ生のパケットをそのまま描くと破綻するのか

権威型サーバー(authoritative server)方式のマルチプレイヤーでは、ゲーム状態の真実はサーバーが握り、各プレイヤーの位置や向きをスナップショットとして定期的に配信します。配信レート(tick rate)は典型的には毎秒20〜64回で、連続的ではありません。60fpsで描画するクライアントから見れば、他プレイヤーの新しい位置情報は数フレームに一度しか届きません。

この離散的なスナップショットを届いた瞬間にそのまま反映すると、他プレイヤーは1秒間に20〜64回だけワープするカクついた動きになります。さらにUDPパケットは到着間隔が揺らぎ(ジッタ)、順序が入れ替わり、時に欠落します。生データを直接描けば、その揺らぎがそのまま画面の震えとして現れます。この問題を、描画の滑らかさ(クライアント側の補間)と、当たり判定の正しさ(サーバー側の遅延補償)という2つの独立した仕組みで解くのが本稿の主題です。

3つの時刻を分けて考える

ネットワークゲームには少なくとも3つの時間軸が同時に存在します。(1) サーバーが状態を確定したサーバー時刻、(2) 自分の操作が即座に反映されるローカル自機の時刻(クライアント予測)、(3) 他プレイヤーを描画する補間時刻(=現在より一定量だけ過去)。自機は遅延ゼロで動かしたいが、他機は滑らかさのためにあえて過去を描く。この「自分は現在・他人は過去」という時刻のズレこそが、後述するラグ補償の公平性問題の根です。

スナップショット補間:あえて過去を描いて滑らかさを買う

エンティティ補間(entity interpolation)の中核は、受信済みの2つのスナップショットの間を内挿して描くことです。ポイントは、クライアントが常に「最新の受信状態」ではなく「少し過去の状態」を描く点にあります。描画時刻を意図的に 補間遅延(interpolation delay、しばしば100ms前後)だけ巻き戻し、その時刻を挟む2つのスナップショットから線形補間で位置を求めます。

補間の基本手順(描画フレームごと):

  render_time = now - interp_delay        // 例: interp_delay = 100ms
  (S0, S1) = render_time を挟む前後のスナップショットを選ぶ
             // S0.t ≤ render_time ≤ S1.t
  alpha = (render_time - S0.t) / (S1.t - S0.t)   // 0..1
  pos   = lerp(S0.pos, S1.pos, alpha)     // 位置は線形補間
  rot   = slerp(S0.rot, S1.rot, alpha)    // 回転は球面線形補間

なぜ過去を描くのか。それは内挿を成立させるには、描こうとする時刻の「後ろ」のスナップショットが手元に届いていなければならないからです。render_time を現在に置くと未来の点が必要になり内挿できません。補間遅延 を確保することで、その分の余裕の中に必ず2点が入り、パケットが1つ欠けても次の点まで滑らかに繋がり、ジッタも吸収されます。代償は他プレイヤーが 補間遅延 + 平均遅延だけ「過去に見える」こと。この見た目の遅れが、後のラグ補償で埋め合わせる対象になります。

補間遅延はスナップショット間隔の2倍が目安

補間遅延 は最低でもスナップショット間隔の2つ分を確保するのが定石です。tick rate が20(間隔50ms)なら100ms、64(間隔約15.6ms)なら30ms強。こうすれば常に前後2点が揃い、1パケット欠落しても内挿を継続できます。短くするほど他機の表示遅れは減りますが、ジッタや欠落に対する耐性が下がり、補間バッファが枯渇して外挿(後述)へ落ちやすくなります。回線品質に応じて動的に調整する実装も一般的です。

外挿(extrapolation):バッファが枯れたら未来を推測する

render_time より後ろのスナップショットがまだ届いていない場合、内挿すべき2点が揃いません。パケットが大きく遅延・欠落したときに起きます。ここで選択肢は2つ。ひとつは他機をその場で停止させて次の受信を待つ(フリーズ)。もうひとつが外挿(extrapolation)で、直近の速度・加速度から未来位置を推定して描き続けることです。

外挿(前方の点が無いとき):

  dt        = render_time - S_last.t          // 最新点からの経過
  pos_guess = S_last.pos + S_last.vel * dt    // 等速仮定で前進
  // 実際に次のスナップショットが届いたら真値へ補正する

外挿は内挿と正反対の性質を持ちます。内挿は確定した過去を描くので必ず正しく滑らかですが、外挿は未確定の未来を描くので、対象が急に止まる・曲がると予測が外れ、真値が届いた瞬間に位置が飛ぶ(rubber-banding)。そのため外挿は短時間(せいぜい数フレーム、100〜250ms程度)に制限し、超過したらフリーズへ切り替えるのが安全策です。等速外挿が基本で、加速度まで見ると誤差が発散しやすくなります。動きが予測しづらいゲームほど外挿は不利で、内挿主体に倒す設計が好まれます。

観点内挿(interpolation)外挿(extrapolation)
描く時刻現在より過去(確定済み)現在より未来(未確定)
必要なデータ前後2つのスナップショット直近1点+速度(加速度)
正確さ常に真値どおり・滑らか誤予測で位置が飛びうる
表示遅延あり(補間遅延ぶん遅れる)小さい/無い(未来を先取り)
破綻の仕方バッファ枯渇でフリーズ急な方向転換でrubber-band
主な用途通常時の他プレイヤー描画パケット欠落時の短時間の穴埋め

ラグ補償:サーバーが「撃った瞬間」へ巻き戻す

ここまでで他プレイヤーは滑らかに、しかし 補間遅延 + 遅延だけ過去に表示されています。プレイヤーが画面上の敵の頭に照準を合わせて撃つとき、その敵はサーバー上の現在位置ではなく過去の位置です。もしサーバーが現在の状態で当たり判定を取れば、狙ったはずの弾はことごとく外れます。速い敵ほど表示位置と現在位置の差が開くため、遅延の大きいプレイヤーは「明らかに当てたのに当たらない」状態に陥ります。

これを解決するのがラグ補償(lag compensation)=サーバー側巻き戻し(server-side rewind)です。サーバーは全エンティティの位置履歴を一定時間ぶんリングバッファに保持しておき、あるプレイヤーの射撃コマンドを受け取ったら、そのプレイヤーが実際に画面で見ていた時刻まで世界を巻き戻し、その過去の状態でヒットスキャンの当たり判定を行います。

サーバー側のラグ補償(射撃コマンド受信時):

  // クライアントが弾を撃った時点で見ていた時刻を再構成
  cmd_time = server_recv_time
             - player_rtt / 2          // 上り遅延ぶん戻す
             - player_interp_delay      // 他機の補間遅延ぶん戻す

  // その時刻の全ヒットボックス位置を履歴から復元(必要なら内挿)
  restore_all_hitboxes_to(cmd_time)

  hit = raycast(shot_origin, shot_dir)  // 巻き戻した世界で判定
  restore_all_hitboxes_to(present)      // 判定後すぐ現在へ戻す

要点は、サーバーが RTT/2(上り片道遅延)と撃った側の 補間遅延 を足し合わせて、そのプレイヤーのクライアント画面と同じ過去の瞬間を復元することです。これにより「自分の画面で頭に合わせて撃った」という主観がサーバー判定と一致し、遅延の大小によらず撃つ側の体験は公平になります。多くの実装ではクライアントが射撃コマンドに自分の見ていたタイムスタンプ(あるいはコマンド番号)を添えて送り、サーバーはそれを検証したうえで採用します(過大な巻き戻し要求はチート防止のため上限でクランプします)。

巻き戻しは撃たれる側の不公平と引き換え

ラグ補償は撃つ側の主観を守る一方、撃たれる側に理不尽を生みます。あなたが角に隠れて安全になったと思った直後に撃たれて死ぬ——遅延の大きい敵から見れば、あなたはまだ角の手前に見えており、サーバーはその過去時刻へ巻き戻して当たりを認めるからです(俗に「angle死」「peeker's advantage」と呼ばれる現象の一因)。これは実装バグではなく、「撃つ側の画面を正とする」という設計判断の必然的な帰結です。巻き戻せる最大時間に上限(例: 200〜250ms)を設け、それを超える遅延のプレイヤーには補償を切る・弱めることで、不公平の最大量を制限します。

公平性のトレードオフと設計判断

横にスクロール

受信スナップショットを過去時刻で補間し射撃時にサーバー状態を巻き戻して命中判定する図
表示補間と遅延補償を分け、履歴上限と射手/標的の公平性を示します。

エンティティ補間とラグ補償は、遅延という物理的制約の下で「誰の主観を正とするか」を選ぶ仕組みです。撃つ側を優先すれば命中体験は良くなるが遮蔽後死(撃たれる側の不公平)が増え、撃たれる側を優先(現在時刻で判定、巻き戻さない)すれば遮蔽は守られるが高遅延プレイヤーはまともに当てられません。中間として、巻き戻し上限を短く保つ、ヒット確定はサーバーだが発砲エフェクトはクライアント予測で即出す、被弾者側の視点でも一定の猶予(favor-the-shooter を弱める)を入れる、といった調整が行われます。

さらに tick rate を上げれば履歴の時間解像度が上がり、巻き戻し精度と応答性が改善しますが、帯域とサーバーCPUのコストが線形に増えます。スナップショットはデルタ圧縮(前回確認済み状態との差分のみ送る)や関心領域(AoI)フィルタ(見えない相手は送らない)で帯域を抑えるのが定石で、これらは補間・補償の基盤となるデータ供給の質を左右します。ネットワーク層のジッタ・パケットロスの扱いはネットワークの原理・プロトコル側の理解が、他プレイヤーを滑らかに見せる補間・外挿の描画はグラフィックス・レンダリングの原理側の理解が土台になります。

試験・実務での判断ポイント
  • 補間は過去・外挿は未来: 内挿は受信済み2点の間を描くため常に滑らかで正しいが 補間遅延 ぶん遅れる。外挿は直近速度から未来を推定するので遅れは小さいが誤予測で飛ぶ。通常は内挿、バッファ枯渇時のみ短時間の外挿。
  • 補間遅延の下限: スナップショット間隔の約2倍。1パケット欠落しても前後2点が揃うようにする。短いほど表示は新鮮だがジッタ耐性が落ちる。
  • ラグ補償の巻き戻し量: RTT/2 + 撃った側の補間遅延。これで撃つ側のクライアント画面とサーバー判定を一致させる。上限クランプでチートと過大補償を防ぐ。
  • 公平性は原理的トレードオフ: 撃つ側を正とすると遮蔽後死が発生。実装バグではなく favor-the-shooter の必然。上限短縮や被弾側の猶予で緩和する。
  • 土台となる最適化: デルタ圧縮・AoIフィルタで帯域を、高tick rateで時間解像度を稼ぐ。帯域とCPUのコストと引き換え。

まとめ

離散的なスナップショットとジッタの多いUDPを前提に、ネットワークゲームは描画と当たり判定を別々の仕組みで滑らかかつ公平にします。エンティティ補間は描画時刻をあえて 補間遅延 だけ過去へ置き、受信済みの前後2スナップショットを内挿することで、疎で不揃いなパケットからでも他プレイヤーを滑らかに描きます。前方の点が届かないときは、直近の速度から未来を推す外挿で短時間だけ穴を埋めますが、誤予測で位置が飛ぶため内挿主体が基本です。こうして他機は過去に表示されるため、サーバーは射撃時に RTT/2 + 補間遅延 だけ世界を巻き戻すラグ補償で、撃った側が見た瞬間の当たり判定を再現します。これは撃つ側の主観を守る反面、遮蔽したはずの撃たれる側に理不尽を強いる原理的なトレードオフであり、巻き戻し上限や被弾側への猶予で最大の不公平を制限します。補間遅延の長さ、スナップショットレート、巻き戻し上限という3つのパラメータをどう設定するかが、そのゲームのプレイ感と公平性の性格を決めるのです。

ゲーム開発の記事ガイド

エンティティ補間と遅延補償を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

ゲーム開発

比較で見る軸

難易度: advanced / カテゴリ: ゲーム開発 / タグ数: 6

導入後に効く点

ラグ補償はサーバーが撃った瞬間のクライアント時刻に全エンティティを巻き戻し、その過去状態で当たり判定を取る。撃った側は『見えたとおり当たる』が、撃たれた側は遮蔽後に撃たれる不公平が原理的に発生する。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
ゲーム開発
タグ数
6

判断チェックリスト

  • 自社の用途が「ゲーム開発 / ネットワーク同期」に近いか確認する。
  • 強みである「サーバーは一定レートでスナップショットを送り、クライアントは受信済みの過去2点を意図的な遅延(補間バッファ)を挟んで内挿することで、パケットが疎でも他プレイヤーを滑らかに描画する。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

ゲーム開発ネットワーク同期遅延補償スナップショット補間当たり判定