lufftec’s diary

ゲームプログラマやってます。技術系中心に自由に書いていきます。

GGPOの公式サンプルを試してみる (1)


GGPOの実際の動作や実装方法に興味があるので、まずは公式サンプルを試してみたいと思います。
その前に、GGPOや格ゲーなどの同期方式について色々書きました。
(簡単に書くつもりが長くなってしまったので、必要ない方は飛ばしていただけたらと思います…)

[目次]

[GGPOとロールバック方式について]


[GGPOとは]

公式ページ

GGPOライブラリは、主にゲームに使われる通信用ライブラリです(特に格ゲー)。
2000年代後半に Tony Cannon さんによって作成され、2019年にMITライセンスでオープンソース化されました。

GGPOの根幹のアイディアであるロールバック方式は、2010年代に色々な対戦ゲーム(主に格ゲー)で取り入れられ、現在の格ゲーでは、ほぼ必須の対応が求められています。

※GGPOライブラリを作った Tony Cannon さんは、格ゲーの大会のEVOの創設者でもあるそうです(ご兄弟の Tom Cannon さんと)。ライブラリのオープンソース化など、格ゲーへの影響が計り知れないですね…。


[ロールバック方式、の前に従来のディレイ方式について]

主に格ゲーで使用されてきた従来の同期方式は、「ディレイ方式」と呼ばれています。
しかし、この方式にはデメリットもありました。海外プレイヤーとの対戦が増えた現在、より良いプレイ体験を提供するために「ロールバック方式」が求められるようになってきた背景があります。
まず、従来の「ディレイ方式」について書いていきます。

※ちなみに「ディレイ方式」は他にも、**「完全同期/入力同期」**と呼ばれたり、 海外のサイトだとよく**「決定論的/ロックステップ」(Deterministic/Lockstep)**とも呼ばれたりします。 基本的にほぼ同じものを指していると思うのですが、文脈や視点が違うのかなと思います。

RTSもほとんど同じ方式ですが、送信情報が生のキー入力じゃなかったりします。

以下、各用語について書いていきます。 (あくまで、私個人の理解と経験に基づくものです)


[完全同期型とは]

主に格ゲーにおいて、従来の方式では、対戦が始まってからあるフレームにおいて、お互いの端末の画面が一致しています。
(ここで言う「画面」とは、ゲームロジックに関わるキャラクターなどの絵についてです。例えば、演出上の背景のパーティクルなどは一致していなくても問題ありません)

「各端末の同じフレームで同じ画面が見えている」ことを、「完全同期型」と呼びます。


[入力同期、入力遅延とは]

主に格ゲーでは、毎フレームのキー入力を送りあい、お互いの端末でゲームを動作させています。
これを、「入力同期」と呼びます。

※ちなみに、基本的な同期情報がキー入力だけなのは帯域的に優しいので、リアルタイム性が求められる格ゲーと相性がいいです。

あるフレームの相手のキー入力を受信してから、該当フレームの自分のキー入力と合わせて、一緒に処理を進めないといけません。
そのため、どうしても「入力遅延」(自端末で入力してから処理を進めるまでの待ち時間)が必要になります。

実装には、少なくとも入力遅延分、自端末の過去の入力を保持するためのバッファが必要です。
(到達順序の入れ替わりやパケロスもあるので、相手端末の入力もバッファを持ちます)

※「ディレイ方式」という呼び方は、この「入力遅延」の部分を大きく取り上げた視点の言葉なのではないかと想像します。格ゲーでは入力遅延がプレイ感に大きな影響を与えるためです。「ロールバック方式」は、この入力遅延問題を大きく改善した方式になります。


[ロックステップとは]

全プレイヤーの入力が揃ってからゲームの進行を行う(フレームを進める)、逆に言うと、揃うまではゲーム進行を停止する、ことを「ロックステップ」と呼びます。

従来、相手のキー入力が届くまでは全く処理を進ませなかったので、通信環境が悪くなると完全に画面が止まり、動作がカクついたりゆっくりになったりしていました。
(例えば、あらかじめ5フレームの入力遅延を入れておけば、5フレームの間に受信できれば処理を進められるが、受信できないと画面が止まる)

このロックステップの仕組みと後述する決定論的なプログラムによって、各端末の見た目の完全同期を実現しています。

カクつきに対する各ユーザーの慣れの度合いはあるにせよ、完全同期型であることは端末間で公平なので、格ゲー(対戦ゲーム)に向いています。


[決定論的とは]

ここまで各用語について話してきましたが、そもそもの大前提の話があります。

ゲームプログラム側は、同じ状態の時に同じキー入力を渡せば同じことが起こるように作っておかないといけません。
(例えば、対戦が始まる前に乱数シードを合わせたり、ゲームロジックに関わるマルチスレッドを禁止したり、異なるアーキテクチャ間の演算結果の違いの対応だったり…)

このように「同じ状態の時に同じキー入力を渡せば同じことが起こる」ことを、決定論的」と呼んだりします。

基本的な送受信がキー入力情報だけで済んでいるのは、ゲームプログラム側が決定論的にできているからです。

※対戦ゲームの同期方式について調べる際、海外のサイトとかだと「Deterministic Lockstep」で検索すると、よく引っかかります。


[ロールバック方式とは(簡単に)]

従来のディレイ方式の問題点であった、入力遅延とロックステップ(画面が止まる)を改善した方式です。

まず、ロールバック方式も決定論的である必要があります。
(巻き戻し、再計算を行うため)

ディレイ方式では、入力が届くまでゲームを進行させませんでしたが、
ロールバック方式では、入力を予測してゲームを進行させてしまいます。
進行させた後に入力が遅れて届いた時、予測した入力と異なる場合は過去のフレームの処理を再実行します。

このことによって、見た目的な齟齬が起きます。 (キャラクターの動作が欠けたり、変更されたり、ワープしたり)

※これだとFPSやMMOなどの非同期型と似た感じがしますが、非同期型は根本的に必要な部分だけを同期するという考え方で、全てのゲームロジックが同じように各端末で実行されるわけではありません。その点非同期型は決定論的なプログラムでなくても大丈夫、ということになります。

とはいえ、各フレームで起きる内部的なゲームロジック自体は端末間で同じものとなるので、 見た目も含めた完全同期ではないものの、完全同期に近いものと言えると思います。

見た目の齟齬が起きることがロールバック方式のデメリットで、 ディレイ方式では見た目も含めて完全に同期できるので、通信環境によってはディレイ方式の方が良い場合もあるようです。
(実際、おそらく入力遅延も少し入れたディレイ方式とロールバック方式のハイブリッドにしているゲームが多いのではないかと思います)


[参考リンク]

ネットゲームの裏で何が起こっているのか
オンラインゲーム 10年の進化と同期方式の選び方
格ゲーのネットコードについて
格闘ゲームで話題になるロールバックの仕組みとは
Netcode Concepts Part 3: Lockstep and Rollback
Netcode Architectures Part 1: Lockstep
Netcode Architectures Part 2: Rollback


[次回…]

前提がとても長くなってしまいましたが…、 次回から、GitHubからSDKをダウンロードして試していきます。

  翻译: