【Unity】数千体のエンティティをリアルタイム同期した話
2025-04-04
azblob://2025/04/08/eyecatch/2025-4-4-unity-photon-quantum-multiplayer-gamedev-000.png

はじめまして 25卒新入社員の竹村です。

私は趣味の一つとしてFPSゲームをよくプレイします。

最近はValorantにお熱ですが、Apex LegendsやDelta ForceなどメジャーなFPSなら大体プレイしています。

ゲーマーなら一度は考えたことがあるかもしれませんが

オリジナルのFPSゲームを作ってみたい!

を実現した経験があるので、今回は私が実際に開発したマルチプレイFPSゲームに用いた技術について解説しようと思います。

企画時点での問題

初めに、今回開発したゲームのコンセプトとして、以下のようなものを掲げていました。

数千体に及ぶゾンビに襲われながら、仲間と協力してゾンビを倒す。

企画書

ゲームを開発したことがある人はわかるかもしれませんが、これを一般的な開発方法で開発をしようとするととても大変です。
特にどのような点に問題があるのかというと、

  • 数千体のエンティティの座標、アニメーション、物理演算などのリアルタイム同期
  • 数千体のエンティティのリアルタイム物理演算・レンダリング

あたりです。

これらの問題を解決するために、様々な技術検証を行いながら開発を進めました。

通信ライブラリについて

まず問題になるのはリアルタイム同期を行うための通信技術です。

一般的なゲームでは、毎秒30回ほど各エンティティの通信をサーバーに対して行っています。(1秒間に10KBぐらい)


しかし、このゲームを開発するにあたって、そのような同期方法を取ってしまうと、1秒間2.5MBほどの通信が必要になります。
これでは通信がパンクしてしまうのは目に見えています。

このような問題を解決しながら開発を進められるように通信ライブラリの選定はゲーム企画に応じて使い分けましょう。

Unityではマルチプレイヤーゲーム開発をするために、様々な通信ライブラリが用意されています。
 

それぞれの特性を理解したうえで、どのライブラリを使用するかを決めると良いでしょう。

  • Netcode(Unity製)
    • Netcode for GameObjects:UnityのGameObjectに特化
    • Netcode for Entities:DOTSを使用してエンティティベースのゲームをネットワーク対応
  • Mirror:オープンソースネットワークフレームワーク
  • MagicOnion:C#と.NETを使用したgRPCをベースにした高速なリアルタイム通信が可能
  • Photon
    • Photon Unity Networking:簡単に実装ができる
    • Photon Fusion:リアルタイム、高速同期が特徴
    • Photon Quantum:物理シミュレーションに特化

以上の特徴を踏まえ、今回使用する通信ライブラリはPhoton Quantumにすることにしました。

Photon Quantumについて

Unityでマルチプレイ開発といえばPhoton!

Photonはインディー界隈ではかなりメジャーで、Among usやVRChatなどもPhotonで動いています。

その中でもPhoton Quantumは、以下のような概要があります。

Photon Quantumは市場で唯一の100%決定性マルチプレイヤーゲームエンジンです。 マルチプレイヤーゲーム制作はローカルゲーム開発と同じくらい簡単になりました。 ネットコードを使わず、デフォルトでネットワーク化かつ完全同期されます。 QuantumでコーディングしてUnityで表示できます。

https://www.photonengine.com/ja-jp/quantum

Photon Quantumの利点として、特筆すべき点が以下のようなものになります。

  • 決定論的なシミュレーションを行うことができる。
  • エンティティコンポーネントシステム(以下ECS)を使うことができる。

このままでは分かりにくいので、それぞれの特徴をゲームの実装部分と重ね合わせながら紹介します。

決定論的なシミュレーション

前述したように数千体のエンティティを毎秒同期するのは非効率であり、現実的ではありません。

しかし、決定論的なシミュレーションを行うことによって、各クライアント間で通信することなく、同期ができてしまうのです!

一般的なエンジンでは、物理演算の結果は非決定的であり、マルチスレッド処理や浮動小数点演算の微妙な違いによって異なる結果が生じることがあります。

例えば、何かしらのシミュレーションを実行したとき、1回目と2回目の実行結果に誤差があることありますよね?

しかし、決定論的なシミュレーションでは、初期状態と規定されたルールから始まり、その後のシステムの状態は完全に予測可能になります。

これは、ゲームの物理演算を含むすべての計算が同じ入力から必ず同じ出力を生成するように設計されているためです。
したがって、各クライアントが同じ入力を受け取り、同じ計算を行う限り、結果は常に一致します。

つまり、シミュレーションを何回実行しても同じ結果が得られる。

言い換えると、

どのクライアントで実行しても同じ結果を得られる。

やりたいことが少し分かってきましたか?

決定論的なシミュレーションを利用することで、プレイヤーのインプットや、ゲーム内イベントなどの最低限の情報を通信するだけで、それに伴う各エンティティの計算や、物理演算などのシミュレーションに対してどのクライアントでも同じ結果を得られるということです。

実際にシミュレーションの同期を確認している様子

このように、決定論的なシミュレーションを利用することで、巨大なマルチプレイヤーゲームにおいて、サーバーとクライアント間のデータ同期の負荷を大幅に減らすことができます。

エンティティコンポーネントシステム(ECS)

近年のゲーム開発では、オブジェクト指向プログラミングが主流ですが、パフォーマンスの観点から考えるとゲームにはあまり向いていません。
なので、今回はECSを使って開発を行いました。

ECSは、ゲーム開発におけるアーキテクチャの一種で、大量のオブジェクトやエンティティを効率的に管理し、処理するために設計されています。

ECSの主な概念は、エンティティ、コンポーネント、システムの3つの要素に分けられます。

  • エンティティ:ゲーム内の個々のオブジェクトを指し、一般的なIDなどの一意の識別子で表されます。
  • コンポーネント:エンティティの特性や状態を表すデータの塊です。例えば、位置、速度、健康状態などがこれに該当します。
  • システム:コンポーネントに対して特定の処理を行い、ゲームのロジックや振る舞いを実装します。物理演算やAIの行動、レンダリングなどがシステムによって処理されます。

ECSは、オブジェクト指向プログラミングにおける継承の代わりにコンポジションを使用することにより、次のように大量のエンティティの処理を高速化することができます。

  1. データ指向設計: ECSはメモリ内でコンポーネントを連続的に配置することを奨励しており、これによりキャッシュの効率が向上し、データアクセスの高速化が図られます。
  2. 並行処理の容易さ: システムは独立しており、特定のコンポーネントのグループに対してのみ動作するため、マルチスレッドや並行処理を効果的に利用できます。これにより、物理演算やAIの計算などの重い処理を複数のコアで並行して行うことができます。
  3. 柔軟な構造: エンティティに必要なコンポーネントを動的に追加または削除することができるため、システムは必要なエンティティに対してのみ処理を行うことができます。これにより無駄な計算を省くことが可能になります。
  4. 最適化されたイテレーション: 同じ種類のコンポーネントを持つエンティティ群に対して、システムは一括して処理を行うことができます。例えば、最短経路検索システムは、ナビゲーションコンポーネントを持つすべてのエンティティの経路を同時に計算することができます。

特に今回のような同じコンポーネント(ゾンビのビヘイビアとか)を大量に処理する際に向いています。

これらの特性を活かすことによって、数千体のエンティティのリアルタイムシミュレーションを実現しています。

これ以外にも、レンダリングやマルチスレッディングなどの問題と解決法のエピソードもありますが、長くなりますのでここらへんで締めたいと思います。

最後に

長々と技術的なことを書き連ねましたが、一本のゲームを作るためには様々な技術、知識、経験が必要になります。

しかし、現代では無料で使えるエンジンやツール、技術資料が溢れていますので、ぜひ皆様もお気軽にゲーム開発をしてみてはいかがでしょうか。

azblob://2025/04/17/eyecatch/2025-04-15-encount-000.jpg
2025/04/17
Others