Chapter 08

🔄 同期方法の選択指針

o8que
o8que
2021.02.04に更新

これまでのチャプターで、3つの同期方法について紹介してきました。PUN2を使ったオンラインゲーム開発では、基本的にこの中から用途・目的に合わせて適切な同期方法を選ぶことになります。以下にそれぞれの特徴を比較して、どれを選択すべきかの基本的な指針をまとめていますので、一つの目安として参考にしてみてください。

同期1 : オブジェクト同期

  • ネットワークオブジェクトのインスタンス(PhotonView)単位で通信が行われる
  • ネットワーク上で同期されるUpdate関数のように使うことができる
  • 通信する頻度が多いデータを同期することに向いているが、そのために通信量が多くなりがち
  • 基本的に自動で通信を繰り返すため、特定のタイミングでのみ通信するような用途には向かない
  • (プロトコルがUDP、PhotonViewの監視オプションで「Unreliable~」を設定した場合)
    到達保証(送信したデータが確実に受信される保証)がないため、重要なデータの同期には使えない

自動で定期的にデータを送受信し続けることに最適化されたRPCとみなせます。リアルタイムで動き回るオブジェクトの座標・向き・アニメーションのパラメーター・UIの値など、更新頻度が多い表示周りのデータの通信に最適です。到達保証がない(ことがある)ので、部分的に情報が抜け落ちてしまうと困るデータを通信する際には、RPCを使うようにしてください。表示周りのデータの通信に最適といっても、例えばターン制シミュレーションの駒(ユニット)のような、数秒~数十秒に一回程度しか座標の移動が発生しない、かつ座標の移動は確実に同期されてほしい場合は、RPCやカスタムプロパティを使った方がよいこともあります。

同期2 : RPC

  • ネットワークオブジェクトのインスタンス(PhotonView)単位で通信が行われる
  • ネットワーク上で同期される関数のように使うことができる
  • (RpcTarget.Allなどで普通に実行した場合)
    汎用的に使えるが、途中参加したプレイヤーには同期されない
  • (RpcTarget.AllViaServerなどでサーバー経由で実行した場合)
    順序保証(実行される順番の保証)がされるため、先着順位を決めたりすることができる
  • (RpcTarget.AllBufferedなどでRPCをバッファリングして実行した場合)
    途中参加したプレイヤーにも同期されるデータの履歴が作れるが、大量の通信と処理が発生する可能性がある

最も汎用的に使える同期方法で、どれを選んだらよいか迷ったなら、とりあえずRPCにしてみるのも悪くありません。通信したいデータが、オブジェクト同期にもカスタムプロパティにも適さないようなら、間違いなくRPCです。各プレイヤーの入力・当たり判定・ゲーム進行関連の通知・その他イベントの処理など、様々な用途の通信に活用できます。もし途中参加したプレイヤーにもデータを同期したいなら、まずはカスタムプロパティで通信できないか検討しましょう。RPCのバッファリングは、例えばチャットや重要な情報などのログを途中参加したプレイヤーでも見られるようにするには便利ですが、履歴が不要なデータの同期では無駄な通信と処理が発生してしまうので使用は控えましょう。

同期3 : カスタムプロパティ

  • プレイヤー(Player)またはルーム(Room)単位で通信が行われる
  • ネットワーク上で同期される変数のように使うことができる
  • 途中参加したプレイヤーにもデータが同期される
  • 文字列のキーを含む必要があるため、その分だけデータのサイズが大きくなりがち
  • 同じ値を複数のプレイヤーが同時に更新を試みると、並行処理に関連する問題が発生することがある

途中参加したプレイヤーにデータを同期する最も簡単な方法です。プレイヤーの状態(スコアやライフなど)・マップ上のアイテム・ルームの共有情報など、必要になった時にいつでも値を取得できるようにしたいデータの通信に適しています。特に更新頻度が少ないデータの通信には最適です。必要なら更新頻度が多いデータの通信に使っても問題はありませんが、文字列のキーを含む分だけデータサイズが大きいので、一秒間で何度も頻繁に更新されるようなデータなら、オブジェクト同期で通信できれば、通信量を削減できるかもしれません。