ロールバックネットコードと予測
対戦ゲームの入力遅延をなくしたい人へ。相手入力を予測してローカルを即応させ、ズレたら過去へ巻き戻して再計算するロールバック方式の原理を押さえれば、格闘ゲーム級の応答性を設計できます。
- ロールバックは未着入力を予測して即時反映し、真の入力と違えば確定フレームへ戻して現在まで再計算する。予測が当たれば入力遅延ゼロ、外れても数フレームの視覚補正で済む。
- 入力待ち方式が常時遅延を払うのに対し、ロールバックは待たずに進め、コストを時折の再計算へ移す。決定的シミュレーションを前提とし、GGPOが代表的な実装だ。
- 成立条件は決定性(同じ状態+同じ入力列から必ず同じ結果)と高速な状態のセーブ/ロード。浮動小数点の非決定性・乱数シード・巻き戻し中の音や演出の抑制など、ビジュアルとロジックの整合を保つ実装上の落とし穴が多い。
遅延方式が「待つ」のに対し、ロールバックは「予測して進み、必要なら巻き戻す」
オンライン対戦ゲームの根本的な問題は、光速と経路の制約から入力がネットワークを渡るのに時間がかかる一方で、格闘ゲームやアクションゲームは1フレーム(60fpsで約16.6ms)単位の応答性を要求する点にあります。従来の遅延(ディレイベース)方式は、あるフレームを進める前に全プレイヤーの入力が揃うのを待ちます。往復遅延(RTT)が大きいほど待ち時間が増えるため、実装は一定の入力遅延バッファを常時挿入して間に合わせます。結果として、通信が滑らかでも自分のボタンが数フレーム遅れて反応する「重さ」を常に支払い続けることになります。
ロールバックネットコードは発想を反転させます。相手の入力がまだ届いていなくても、予測した相手入力を使ってローカルのシミュレーションを止めずに先へ進めます。自分の入力は即座に反映されるため、通常時の入力遅延はゼロです。後から相手の真の入力が届いたとき、予測と一致していれば何もする必要はありません。もし食い違っていたら、その入力が確定していた過去フレームまでゲーム状態を巻き戻し(ロールバック)、正しい入力列で現在フレームまで一気に再シミュレーションして辻褄を合わせます。「待たずに予測で進む。外れたら巻き戻して計算し直す」——この構造がロールバックの核心です。
ロールバックは (1) 決定的シミュレーション(同じ開始状態と同じ入力列を与えれば、どの環境でも必ず同一の結果になること)、(2) 高速な状態のセーブ/ロード(任意フレームのゲーム状態を保存し、後で瞬時に復元できること)、(3) 入力予測とロールバック再計算のループ(未着入力を予測し、確定入力とのズレを検知して巻き戻す機構)の3つで成り立ちます。決定性がなければ「巻き戻して同じ入力を流せば同じ状態に戻る」という前提自体が崩れ、再計算結果が発散します。
決定的シミュレーション:巻き戻して再計算できる前提
ロールバックの土台は決定性(determinism)です。ゲームロジックを「現在の状態 S と全プレイヤーの入力 I を受け取り、次フレームの状態を返す純粋な遷移関数 S_next = step(S, I)」として設計します。この関数が副作用や環境依存を持たず、同じ S と I から常に同じ S_next を返すなら、確定フレームから同じ入力列を流し直すだけで、まったく同一の現在状態を再構築できます。逆に言えば、状態遷移に関わる要素はすべてこの決定的な計算の内側に閉じ込めねばなりません。
- 浮動小数点の非決定性: CPUアーキテクチャ・コンパイラ・最適化設定の違いで
float演算の丸めが変わり、異なる環境間でシミュレーションが少しずつ食い違う。クロスプラットフォーム対戦では固定小数点演算に切り替えるか、演算順序と精度を厳密に固定する必要がある。 - 乱数: 乱数を使う場合はシードを状態に含め、生成器を決定的に進めること。システム時刻や真の乱数源に依存すると再計算で結果が変わる。
- 状態の取りこぼし: セーブ/ロード対象から漏れた変数(オブジェクトプールの内部カウンタ、タイマーなど)が1つでもあると、巻き戻し後の再計算が元と一致せず不整合が生じる。
- 反復順序: ハッシュマップの列挙順など、環境で変わりうる順序に依存した処理は非決定性の温床になる。
決定性はネットワークの効率にも直結します。全員が同じ step を実行できるなら、ネットワークで送るのは入力だけでよく、ゲーム状態そのものを同期する必要がありません。1フレームの入力はボタンの押下状態を表す数バイトに収まるため、帯域は極めて小さくて済みます。これは各クライアントが独立に世界全体を並行計算するロックステップ的な同期モデルであり、リアルタイム計算という点で/os/のスケジューリングや/network/の遅延特性の理解が土台になります。
入力予測とロールバック再計算のループ
横にスクロール
決定的な step とセーブ/ロードが揃うと、各フレームの処理は次のループになります。
毎フレームの処理(プレイヤー視点):
1. 自分の入力を採取し、即座にローカルへ反映(遅延ゼロ)
2. 相手の入力を確認:
・届いていれば → 真の入力を使う
・未着なら → 予測(多くは「直前フレームと同じ入力」)
3. step(現在状態, {自分の入力, 相手の入力}) で1フレーム進める
4. 予測に使った相手フレームの真の入力が後から到着したら:
(a) 予測と一致 → 何もしない
(b) 食い違い → ロールバック発生:
・その入力が確定していたフレームの保存状態をロード
・確定した入力列で現在フレームまで step を連続実行(再計算)
・巻き戻し中の描画・音・演出は抑制(後述)
未着入力の予測は、格闘ゲームでは「相手は直前のフレームと同じ入力を続けている」と仮定する単純なモデルが定番です。人間の入力は多くのフレームで前フレームと変わらないため、この素朴な予測でも大半のフレームは的中し、ロールバックが起きません。予測が外れるのは、相手がちょうどそのタイミングでボタン状態を変えたときだけで、しかもRTTが小さいほど「予測に頼るフレーム数」が減るため、ミスの機会そのものが少なくなります。
ロールバックで戻すのは「食い違った相手入力が本来入るべきだったフレーム」までです。そこから現在フレームまでは、すでに手元にある確定入力列を使って step を連打し、状態を作り直します。ここで自分の入力は当時実際に押したものが履歴として残っているため、再計算しても自分の操作は変わりません。変わるのは相手の入力を反映した結果だけです。だから「相手のパンチが実は数フレーム前に出ていた」といった補正が、自分の操作感を損なわずに反映されます。1回のロールバックで再計算するのは高々『予測に頼っていたフレーム数』分であり、通常は数フレームなので、60fpsの1フレーム予算内に複数回のstepを詰め込めます。
再計算の量は「予測で先走った距離」に比例します。ロールバック可能な最大フレーム数(ロールバックウィンドウ)を上限として設け、これを超えて相手入力が届かない場合は、遅延方式のように相手を待つ・接続を切るなどの縮退動作へ移行します。RTTが大きいほどウィンドウを広く取る必要があり、その分1回の再計算コストと予測ミス確率が上がる——ここに帯域ではなく計算量でトレードオフを払うロールバックの性質が表れます。
GGPO方式と遅延隠蔽、そしてビジュアル整合
この予測+ロールバックの枠組みを対戦ゲームで実用化した代表的な実装がGGPO(Good Game Peace Out)です。GGPOはピア間で入力だけを交換し、各クライアントがローカルで決定的シミュレーションを進め、確定入力とのズレを検知して自動で巻き戻すという一連の仕組みをライブラリ化しました。ゲーム側は「状態のセーブ/ロード」「1フレーム進める」「入力の受け渡し」のコールバックを実装すれば、遅延隠蔽の面倒をライブラリに委ねられます。
遅延隠蔽の観点で決定的に重要なのは、ロールバック中の再計算をプレイヤーに見せないことです。巻き戻し→再計算は1フレーム予算の内側で完結する内部処理であり、画面には最終的に辻褄の合った現在フレームだけを描きます。しかしここで、ロジックの再実行が視覚・聴覚の副作用まで巻き戻せないという整合性の問題が生じます。
- 音の多重再生: ヒット音や足音の再生を
stepの中で直接鳴らすと、ロールバックで同じフレームを何度も再計算するたびに音が重複発火する。効果音は「ロジック上の発生」と「実際の再生」を分離し、再計算中(巻き戻し replay 中)は再生を抑制して、確定した最新パスでのみ鳴らす。 - パーティクル・演出の再生成: エフェクトの生成も同様に再計算で重複・ちらつきを起こす。演出は決定的状態から毎フレーム導出できるよう設計するか、replay 中は生成を止める。
- 予測ミスの見た目の飛び: 予測が外れると、巻き戻し後の再計算でキャラ位置が数フレーム分ワープしたように見えることがある。RTTが小さいほどこの飛距離は小さく、多くの場合は知覚しづらい。位置の見た目だけを補間で滑らかに寄せる手法もあるが、あくまで表示層に限定し、判定に使うロジック状態は決定的な真値のまま扱う。
このため実装では、ロジック層(決定的で巻き戻し対象)と表示・演出層(非決定的で巻き戻さない/replay中は抑制)を明確に分離するのが定石です。再計算はロジック層だけを何度でも回し、音・エフェクト・カメラといった副作用は「確定した最終フレームの一度きり」に紐づけます。この分離は描画パイプラインの知識とも関わり、/graphics/の合成やレンダリング理解が表示層の設計に効いてきます。
| 観点 | 遅延(ディレイベース)方式 | ロールバック方式 |
|---|---|---|
| 進行のタイミング | 全員の入力が揃うまで待つ | 予測で待たずに進める |
| 通常時の入力遅延 | 常に一定の遅延を支払う | 原則ゼロ(予測が当たる限り) |
| 遅延コストの付け替え先 | 毎フレームの待ち時間 | 予測ミス時の巻き戻し再計算 |
| ネットワークで送るもの | 入力(同期待ちあり) | 入力のみ(待たず先行送信) |
| 主な負荷 | 帯域よりも待機時間 | CPU(再計算)と状態保存メモリ |
| 決定性の要求 | 必要(ロックステップ) | 必須(巻き戻し再計算の前提) |
| 体感 | 回線相応に重くなる | 軽いが予測ミス時に見た目が飛ぶ |
- 予測とロールバックの流れ: 未着の相手入力を予測してローカルを止めずに進め、真の入力とのズレが判明したら確定フレームまで状態を巻き戻し、確定入力列で現在フレームまで再シミュレーションする。
- 成立条件: 決定的シミュレーション(同じ状態+同じ入力列 → 同じ結果)と、任意フレームの高速なセーブ/ロード。どちらか欠けると再計算が発散する。
- 遅延方式との本質差: 遅延方式は全員の入力を待って一定の入力遅延を常時払う。ロールバックは待たず、遅延コストを『たまの巻き戻し再計算』へ付け替えるため通常時は遅延ゼロ。
- GGPO: 入力交換・セーブ/ロード・巻き戻しをライブラリ化し、この方式を対戦ゲームで普及させた代表的実装。ゲーム側はコールバック実装で組み込める。
- ビジュアル整合: 再計算で音・エフェクトが多重発火しないよう、決定的なロジック層と巻き戻さない表示層を分離し、replay 中は副作用を抑制する。予測ミス時の見た目の飛びはRTTが小さいほど小さい。
まとめ
ロールバックネットコードは、相手の未着入力を予測してローカルシミュレーションを止めずに進め、真の入力が届いてズレが判明したら確定フレームまで状態を巻き戻し、確定した入力列で現在フレームまで一気に再計算して整合を取る手法です。土台となるのは決定的シミュレーション、すなわち同じ状態と同じ入力列から必ず同一結果が得られる純粋な状態遷移であり、これにより送るべきデータは入力だけに縮小され、任意フレームの再構築が可能になります。遅延(ディレイベース)方式が全員の入力を待って一定の入力遅延を常時支払うのに対し、ロールバックは待たずに進めて通常時の遅延をゼロにし、コストを『たまに起きる巻き戻しの再計算』というCPU・メモリ側へ付け替えます。GGPOがこの方式を実用化し、入力交換とセーブ/ロードと巻き戻しをライブラリとして普及させました。実装の勝負どころは、浮動小数点や乱数・状態の取りこぼしといった非決定性を排し、かつ再計算のたびに音や演出が多重発火しないよう、巻き戻し対象の決定的なロジック層と、巻き戻さない表示・演出層を分離してビジュアル整合を保つことにあります。帯域ではなく計算量で遅延を隠すこの設計思想ゆえに、1フレームの応答性が勝敗を分ける格闘・アクション系の対戦では、ロールバックが第一の選択肢になっています。
ゲーム開発の記事ガイド
ロールバックネットコードと予測を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
ゲーム開発
比較で見る軸
難易度: advanced / カテゴリ: ゲーム開発 / タグ数: 6
導入後に効く点
入力待ち方式が常時遅延を払うのに対し、ロールバックは待たずに進め、コストを時折の再計算へ移す。決定的シミュレーションを前提とし、GGPOが代表的な実装だ。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- ゲーム開発
- タグ数
- 6
判断チェックリスト
- 自社の用途が「ゲーム開発 / ネットコード」に近いか確認する。
- 強みである「ロールバックは未着入力を予測して即時反映し、真の入力と違えば確定フレームへ戻して現在まで再計算する。予測が当たれば入力遅延ゼロ、外れても数フレームの視覚補正で済む。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。