概念的には、ゲームでリプレイはどのように機能しますか?


145

ゲームでリプレイがどのように実装されるかについて、私は一種の好奇心を持っていました。

最初は、ゲームで行われたすべてのプレイヤー/ aiアクションのコマンドリストがあるだけだと思っていたので、ゲームを「リプレイ」して、エンジンを通常どおりにレンダリングしました。ただし、FPS / RTSゲームのリプレイを確認しました。注意深く調べたところ、粒子やグラフィック/音声のグリッチなども一貫しています(これらのグリッチは一般一貫ています)。

これはどのようにして起こりますか?固定カメラアングルゲームでは、保存されたストリームにシーン全体のすべてのフレームを書き込み、ストリームを再生するだけかもしれませんが、カメラを一時停止して移動できるゲームには十分ではないようです。周り。すべての時点でシーン内のすべての場所を保存する必要があります(いいえ)。パーティクルなどの場合、これはプッシュする大量のデータであり、プレイ中のゲームのパフォーマンスを大幅に引き出すように見えます。


10
オリジナルのスタークラフトリプレイは実際には一貫性がありませんでした。同じゲームを2回見ると、かなり異なる結果が得られます。
Andres

1
@Andres:興味深いことに、私は気づかなかった。特に、RTSのジャンルについては、Company Of Heroesについて考えていました。
Steven Evers

4
SnOrfusが求めていることを明確にするために:一部のゲーム(Uncharted 2、Halo 3、Battlefield 2でも)では、ゲーム全体を記録できます。ゲーム終了後、指定された速度でプレイバックし、アクションの実行中にレベルを飛行して、マップ内の任意の位置から表示できます。だから私はそれがすべてのプレイヤー/オブジェクトの動きを記録することに関するものであり、ビデオバッファとは関係がないと思います。
ショーン

1
@Sean O'Hollaren:はい、そうです。
Steven Evers

1
次に、リプレイがほぼデフォルトであるカーレースゲームも追加します。モデルの場所が記録され、すべてがエンジンを通過するだけだと確信しています。
d -_- b 2010

回答:


61

あなたの最初の考えは正しかったと思います。再生を作成するには、ユーザーから受け取ったすべての入力を、それを受け取ったフレーム番号とともに、乱数ジェネレーターの初期シードとともに保存します。ゲームをリプレイするには、保存したシードを使用してPRNGをリセットし、ゲームエンジンに同じ入力シーケンス(フレーム番号に同期)を供給します。多くのゲームは、フレーム間で経過する時間に基づいてゲームの状態を更新するため、各フレームの長さを保存する必要がある場合もあります。


リプレイはライブゲームとは異なるフレームレートで実行される可能性があるため、フレーム番号は適切な参照ではない可能性があります。
ベンS

5
@ベン:フレーム数は変わらないので、フレームレートは違いを生じません。これが正解です。
BlueRaja-Danny Pflughoeft

14
グラフィカルフレームとエンジンの「フレーム」(または反復)は必ずしも同じではありません。多くの古いゲームでは、エンジンは1つのマスターループでグラフィックスと同じレートで更新されていました。最新のエンジンでは、GPUが許す限りの速さでグラフィックを更新でき、エンジンがゲームダイナミクス(多くの場合、物理エンジン)の良好で一貫した解像度に必要なレベルで動作します。
ダンブライアント

3
@iamgopal:疑似乱数ジェネレータの状態がわかっている場合、その問題はすでに解決されています。別の方法は、乱数を別の形式の入力として扱い、キープレスなどと一緒にそれらを保存することです。
Kylotan、

1
このアプローチでは、ゲームエンジンが確定的であり、一定のタイムステップで動作する必要があることをお伝えします。BlizzardのRTSゲームはすべてこの方法で構築されたと思います。非決定的ゲームには、長期的に一貫性を確保するために追加の同期データが含まれます。
ジョンライデグレン

28

StarcraftおよびStarcraft:Brood Warにはリプレイ機能がありました。試合が完了した後、リプレイを保存して後で表示することができます。再生中に、マップをスクロールしてユニットや建物をクリックすることはできますが、それらの動作は変更できません。

元のゲームでプレイされた試合のリプレイを見たことがありますが、そのリプレイはブラッドウォーで見られていました。なじみのない人のために、Blood Warには、元のユニットと建物のすべて、およびさまざまな新しいユニットと建物が含まれています。元のゲームでは、プレーヤーはコンピューターが簡単に対抗できないユニットを作成してコンピューターを打ち負かしていました。ブルードウォーでリプレイをプレイしたとき、コンピューターはさまざまなユニットにアクセスできました。そのため、同じファイルを再生しても、Starcraftのどのバージョンがファイルを再生しているかによって、勝者が異なります。

私はいつもこのコンセプトに魅力を感じました。プレーヤーのすべての入力を記録することでリプレイ機能が機能し、コンピューターがそれらの刺激に毎回まったく同じ方法で応答すると想定したように思われます。プレーヤーの入力が元のStarcraftリプレーヤーに送られると、ゲームは元の試合とまったく同じように再生されました。まったく同じ入力がブルームウォーリプレーヤーに供給されたとき、コンピューターは異なる反応を示し、より強力なユニットを作成し、ゲームに勝ちました。

再生エンジンを作成している場合に覚えておくべきこと。


6
+1:非常に興味深い。それについて聞いたことがなかった。彼らがどのようにそれを開発したかについてのいくつかの良い洞察を提供します。
Steven Evers 2010年

18

主な方法は2つあります。

  1. イベント(プレーヤー/ aiアクションなど)の保存-ちょうどあなたが言うように。
  2. 状態の保存(完全なゲームの状態、オブジェクトの位置、連続した瞬間)。

何をしたいかによります。通常はメモリの消費量がはるかに少ないため、イベントを保存する方が良い場合があります。反対に、さまざまな速度で、さまざまな開始点から再生できる再生を提供する場合は、状態を保存することをお勧めします。状態を保存するときに、すべてのイベントの後に保存するか、毎秒12または25回のみ保存するかを決定することもできます。これにより、再生のサイズが小さくなり、巻き戻し/早送りが容易になる場合があります。

「状態」はグラフィカルな状態を意味しないことに注意してください。ユニットの位置、リソースの状態などのようなもの。グラフィックス、パーティクルシステムなどは通常、確定的であり、「アニメーションX、時間Y:Z」として保存できます。

時々、リプレイは不正行為防止スキームとして使用されます。次に、イベントを保存することはおそらくここで最高です。


10

技術的には、ランダム性ではなく、確定的になるようにエンジンを記述する必要があります。ゲーム内のキャラクターが対戦相手の腕を狙っており、武器を発砲していると仮定すると、すべての場合において同じ量のダメージが対戦相手に適用されます。

爆弾が場所Xで爆発すると仮定すると、その爆発によって生成された粒子は常に同じ視覚的結果をもたらすはずです。ランダム性が必要な場合は、一連の乱数を作成し、ゲームのプレイ時にシード値を選択し、そのシード値をリプレイに保存します。

一般に、ゲームにランダム性を持たせることは悪い考えです。マルチプレーヤーのようなものでも、爆発の周りでプレーヤーの半分を見ることができませんが、他のプレーヤーは正しいランダム値を取得しなかったためにそれを見ることができません。

すべてを確定的にし、あなたは大丈夫です。


1
AIはどうですか?AIはランダムではありませんか?
ジェシージャシンスキー

18
それは本当に必要ではありません。すべてのランダムイベントにシードされた疑似乱数を使用し、シードをリプレイファイルに保存します。このようにして、再生中に同じ「ランダムな」番号が生成されます。
ベンS

13
-1は、コンピューターでの「ランダム性」の動作についての明確な誤解
BlueRaja-Danny Pflughoeft

10
ええと……いや……「本当の」ランダム性などないことは完全に承知しています。しかし、ほとんどの人は、ランダムシードをシステム時間のようなものに設定することによってこれを回避しようとします。しかし、私が言っているのは、そのようなことはすべきではないということです。彼がシステムAPIを使用しているか、事前定義された乱数のテーブルを使用しているかは、気にしません。私が最初に言ったことは正しかった。彼のエンジンのすべての関数は、その入力に基づいて同じ結果を生成する必要があります。時間は決して重要ではありません。
ティモシーボールドリッジ

2
パーティクルが意味のある方法でゲームメカニクスと相互作用しない場合、RNGが異なるかどうかは問題ではありません。これは、ネットワーク同期シミュレーションの場合に役立ちます(ほとんどのRTSゲームや他の多くのジャンルのゲームの場合のように)、シミュレーションがフレームごとに同期する必要が少し少ないためです(パーティクルエフェクトは単に個別に更新されます)。
RCIX

10

初期状態タイムスタンプ付きの一連のアクションが与えられた場合、記録されたアクションが発生すると想定されているため、シーケンスを実行するだけで再生されます。

ランダムイベントをまったく同じように再発生させるには、シードされた疑似乱数を使用して、シードを再生ファイルに保存します。

同じアルゴリズムを使用してシードから乱数を生成する限り、ゲームの状態の完全なスナップショットを必要とせずに、ライブゲームで発生したとおりにすべてのイベントを再作成できます。

これにはリプレイを順番監視する必要があります、ゲームのリプレイではこれはかなり正常です(Starcraft 2を参照)。タイムラインへのランダムアクセスを許可する場合は、設定された間隔(たとえば1分ごと)で完全な状態のスナップショットを取得し、設定された細分度でタイムラインをジャンプできます。


特定の秒数(たとえば5または10)ごとに再シードすると、リプレイストリームに記録し、前方または後方にジャンプする(基本的にはPRNG "キーフレーム"に)ことができます。
ウェッジ

7

NVidia PhysX(ゲームでよく使用される物理シミュレーションエンジン)は、時間の経過とともに物理シーンの完全な状態を記録できます。これには、ゲームエンジンからの駆動入力が組み込まれているため、他の人が示唆しているように、乱数シードを追跡する必要はありません。このシーンダンプを取得すると、外部ツール(NVidiaが提供)で再生できるため、物理モデルの問題を追跡するのに非常に便利です。ただし、同じ物理ストリームを使用してグラフィックエンジンを駆動することもできます。これにより、グラフィックを駆動する物理のみが記録されているため、通常のカメラ制御が可能になります。多くのゲームでは、これにはパーティクルエフェクトが含まれます(PhysXには非常に洗練されたパーティクルシステムが含まれます)。サウンドに関しては、それが(サウンドストリームとして)逐語的に記録されていると思いますが、


4

あなたの元のアイデアは正しいです、そして本当に複雑な効果のために、それらは排他的に記憶されません。たとえば、Warcraft 3再生システムはアニメーションの状態、またはランダムエフェクトの場合はパーティクルエフェクトなどを保存しません。さらに、ほとんどのシステムでは、ほとんどのシステムで開始点から決定論的な方法で計算することができます。ランダム変数(ランダムオフセットを与えるパーティクル爆発など)を使用する場合、必要なのはエフェクトの時間とランダムシードだけです。その後、最終的にどのように見えるかを実際に知らなくても、効果を再生成できます。決定論的なコードパスを通過していることを知っています。

純粋に概念的に考えると、イベントのタイムラインを再生するには、ユーザーのアクションだけが必要です。プログラムは、ランダム変数の場合を除いて、まったく同じように反応します。このシナリオでは、ランダム性を無視するか(効果がまったく同じであるか、またはランダムに再生成できるかどうかが本当に重要か)、シード値を保存してランダム性を偽ることができます。


3

2ペンスを投入します。

何をしたいかによりますが、リプレイは

  1. ビデオバッファの記録と後での再生
  2. フレームごとにオブジェクトの状態をキャプチャし、後で再生します。

ほとんどの場合、人々はインタラクティブなリプレイを望んでいるので、2。がその方法です。次に、制約に応じて、このプロセスを最適化する方法がいくつかあります

  • すべての入力が一貫した期待される出力を生成するように、システムが確定的なシミュレーションであることを確認します*
  • ランダム性が必要な場合は、後で乱数を正確に再現できるようしてください[疑似乱数ジェネレーターPRNGを使用してシードすることを確認するか、既定のランダムセットを使用してください]
  • ゲームの要素を「メカニック」要素と「美的」要素に分割します。機械的要素は結果に影響します(たとえば、柱の転倒やパスの遮断)、美的要素は表示用であり、システムの意思決定プロセスには影響しません(たとえば、火花のような視覚的な粒子効果)。

それは本当に興味深いトピックです。オリジナルのXbox Wrecklessのローンチタイトルが1つあることを覚えています優れた再生機能があったいます。残念ながら、1回以上、リプレイが失敗します;)

ええ、どのようにしてBlinx Time Sweeperを忘れることができますか?実際のゲームメカニックに組み込まれた優れたインタラクティブなリプレイ!


* =時間ステップに関するコメントがあるようです。ここでは「シミュレーション」を使用して、この機能をキャプチャしています。コアでは、エンジンは離散的な時間フレームを生成できる必要があります。再生フレームが元のフレームよりも処理に時間がかかる場合や短い場合でも、システムは同じ時間のデルタが経過したことを認識する必要があります。これは、記録された各入力でフレームタイムステップを記録し、このデルタをエンジンクロックに供給することを意味します。


2

おそらく、各プレーヤーが送信するコマンドのスタックを単純に保存することができます。したがって、爆弾が特定の時点で爆発することや、特定の車が破壊されることを保存する代わりに、各プレイヤーが送信したキーの押下を保存するだけです。次に、リプレイでは、それらのプレスで発生するのと同じようにゲームをシミュレートします。スペースを取らない可能性があるように感じますが、そのような再生システムに取り組んだことはありません。

興味深い質問ですが。プロのゲームでそれがどのように行われるかに興味があります。


2

ダン・ブライアント

さらに、ランダムな進行は、ランダム性に依存するすべてのロジックで特別なサポートがなければ可逆的な手順ではないため、ランダムシードの記録は巻き戻しのサポートには十分ではありません。ランダム操作の結果をイベントストリームの一部として記録する方が柔軟性があります。

ゲームが毎回同じように再生されるように、それがどのように行われたのかを理解しようとしていたときに私が最初に考えたのはまさにそれです。ドゥームで、私はシュートがどれだけランダムになるかを考えました:D。使用された乱数を保存します。解決策になる可能性があることがわかりました。それは、Crysisテクノロジーに関するPDFペーパーに出くわす前のことです。一部のテクスチャノイズと草または木の配置は、固定の可逆シードを使用して疑似ランダム化を使用しているように見えたため、ノイズ、木、および芝の配置の変更は、いつでも見られませんでした。

同時に回避して、何百万本もの樹木や草軸の位置を保存します。どうやら疑似ランダムシーケンスは、論理が固定されているのでいつでも同じように再生でき、統計的にランダムな数値のシーケンスを作るだけです。


これにダンの注意を引きたい場合は、彼の貢献の下にコメントを追加します。そうしないと、彼はおそらくそれを見ることができません。
2013

それが私が単なるゲストの原因である可能性がありますが、親の投稿に「コメントの追加」機能がありませんでした。ダンは返信しました。ダンの返信は言うまでもありません。私のものではない投稿に対しても、編集機能があることがわかりましたが、これはどのように機能しますか?
匿名

ああ、いい質問です!ここにいるようだ私の謝罪-あなたは自分以外の質問も回答にコメントへの50個の担当者のポイントが必要であること。ただし、50は非常に簡単に取得できます。通常、2、3の有用な貢献だけでそれを実現できます。はい、他の人の質問と回答を編集できますが、編集内容は2000年に到達するまで他のユーザーによってレビューされます権限のグラフはこちらを参照してください。
2013

1

一貫したリプレイを行うことの問題は、一貫したマルチプレイヤーゲームの場合と同じです(まあ、簡単です)。

前述したように、RTSゲームでのリプレイは、すべての入力を記録することで保存されます(これは効果があります。スクロールは効果がありません)。マルチプレイヤーもすべての入力を送信します。

単なる推測ではなく、すべての入力を記録します。これは、Warcraft3のリプレイを読み取るためのライブラリで明らかになっています。

入力には、この回答のタイムスタンプが含まれています。


いいえ、それは一貫したMPゲームと同じ(または簡単)ではありません。MPをプレイしているとき、ゲームでは通常、全員が同じバージョンのゲームを持っている必要があります。これは、保存されているセッションの場合とは限りません(古いバージョンのゲームで保存されている可能性があるため)。プレイヤーの1人がAI対戦相手である場合、これは特に重要です。記録されたバージョンよりも新しいバージョンでユニットの攻撃ポイントが1つだけ多いゲームをリプレイすると想像してください。これは、まったく異なる結果につながる可能性があります。
drakon、2015

-1

私は、一定の増分でゲームがすべての状態のスナップショットを撮ると信じています(すべて)。次に、再生が行われているときに、線形補間の簡単な使用法を使用して「穴」を埋めることができます。少なくともそれは私がそれが行われるだろうと思う方法です。

入力の記録は信頼できない/同じ出力を保証しないというのは正しいことです。ゲームは間違いなくすべてのオブジェクト(または少なくとも重要なオブジェクト)の状態を追跡する必要があります


2
いいえ、同じ入力を供給すると、最初とまったく同じ結果になります。タイミングが正しいことを確認し、最初に受信したのと同じフレームの間に入力を入力する必要があります。ゲーム状態全体を定期的に保存すると、膨大な量のメモリが必要になり、一貫性のない結果が生成される可能性もあります。
Peter Ruderman、2006年

@Peter、「同じ入力を供給すると、まったく同じ結果になります」:いいえ。多くのゲームにはランダムな要素があり、リプレイが再生されるたびに異なる場合があります。入力以外の情報も追跡する必要があります。
houbysoft

それは本当だ。また、PRNGのシードを保存する必要もあります(この質問に対する私の回答を参照してください)。
Peter Ruderman、2006年

1
私はそれがパフォーマンスとメモリを消費していることを知っていますが、入力またはランダムジェネレーター、または実際には何でも1つの小さなことを見逃すと、恐ろしい接線で再生が始まります!
Bob Fincheimer

@BlueRaja、ボブのメモリスナップショットのアイデアは、必ずしもすべてのメモリをエンコードするのではなく、状態の「デルタ」を記録することができますが、必ずしもそれほど遠くまでは行きません。これはおそらく、エンジンレベルでサポートする方が簡単です。さらに、ランダムな進行は、ランダム性に依存するすべてのロジックで特別なサポートがなければ可逆的な手順ではないため、ランダムシードを記録するだけでは巻き戻しのサポートには不十分です。ランダム操作の結果をイベントストリームの一部として記録する方が柔軟性があります。
ダンブライアント
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.