PUNからの移行
はじめに
この記事は、オブジェクトの同期とゲームプレイに焦点を合わせて、PUNからFusionに移行する方法を説明します。
PUNは非常に完成度が高く使いやすいネットワーキングソリューションですが、時代が進むにつれて、大人数のプレイヤー数、状態の正確なレプリケーション、権限の取り扱いなど、現代的なマルチプレイヤーゲーム開発に対応しきれない点も出てきました。FusionはPUNと同様の使いやすさながら、より多くのプロジェクトに適したものとなるでしょう。
PUNとの違い
PUNからの移行の際には注意すべき点がいくつかあります。
FusionはプレイヤーごとにNetworkRunnerをインスタンス化し、シーン内でセットアップする必要があります。HierarchyパネルのコンテキストメニューにはFusionのサブメニューがあり、シーンをセットアップする便利なショートカットが存在しています。
Fusionは、主にテストやデバッグの目的で、一つのプロセス内でNetworkRunnerインスタンスを複数実行することができます。エディタのヘルパーパネルから、どのインスタンスの表示や入力を有効にするかを選択できます。
エディタ上で同時に複数のピアを実行している場合、ゲーム開始時に現在のシーンの再読み込みが行われます。これに対応するには、ゲームロジックを調整する必要があります。スタンドアロンビルドは、PUNと同じように簡単にエディタに接続することができます。
PUNの多くのAPIはPhotonNetworkクラスから使用可能でした。Fusionではかわりに、インスタンスごとのNetworkRunnerがあります。SimulationBehaviourかNetworkBehaviourを継承するクラスは、NetworkRunnerとオブジェクトの変数にアクセス可能なため、FusionのAPIはPUNと同様に簡単に扱えます。
PUNでは「分散型」の権限のみを提供していましたが、Fusionはサーバーモード、ホストモード、共有モードに対応しています。共有モードはPUNと似ており、ネットワークオブジェクトの権限が各プレイヤーに分散されます。シーンオブジェクトは自動的に一人のプレイヤーのコントロール下に置かれます。
PUNはオブジェクトに対する所有権のみがあったのに対して、Fusionでは権限が状態権限と入力権限に分けられています(共有モードを除く)。
PUNのスクリプトでは、クライアントがオブジェクトの所有権を持っているかどうかはphotonView.IsMineをチェックするだけで判定できました。FusionではObject.HasStateAuthorityとObject.HasInputAuthorityが別々に保持されています。PUNからFusionへの移植は、共有モードを使用してHasStateAuthorityを確認することになるでしょう。
PUNでは、新しいプレイヤーが入るごとにPlayer.ActorNumberが増加していました。Fusionでは、PlayerRefの値は0から始まりMaxPlayers - 1まで増加します。ゲームのホストが存在する場合、そのプレイヤーのPlayerRefの値は常にMaxPlayers - 1になります。
FusionはUnityのシーンを認識する必要があります。シーンはUnityのBuild Settingsで設定したものが読み込まれます。
PUNとの類似点
FusionはPUNとは大きく異なるように見えますが、実際には多くのアイデアがPUNから引き継がれています。
PUNの重要な要素であるPhotonViewと全く同等なクラスはNetworkObjectと呼ばれます。PUNと同様に、NetworkObjectは単なるIDであり、任意の振る舞いはオブジェクトに追加したコンポーネントに依存することになります。
FusionにはPUNのコンポーネントの代替が用意されています。例えば、PhotonRigidbodyViewはNetworkRigidbodyに置き換えられ、PhotonTransformViewはNetworkTransformになります。PUNと同様に、どちらも2Dでも使用可能です。
PhotonAnimatorViewはNetworkMecanimAnimatorで置き換えられます。キャラクターを操作する用途では、FusionはPUNには無い汎用的なNetworkCharacterControllerがあります。
コンポーネントの個々の設定は異なりますが、多くの場合はデフォルトの値で問題ありません。NetworkObjectとその子オブジェクトの全コンポーネントは、自動的に検出されます。Fusionは必要に応じたNetworkObjectの入れ子構造を完全にサポートしています。
PUNと同様に、NetworkObjectはあらかじめシーン上に置いたり、ランタイム時にインスタンス化したりすることができます。Fusionでは、PhotonNetwork.Instantiate()のかわりにRunner.Spawn()を呼び出します。シーンを読み込むには、PhotonNetwork.LoadLevel()をRunner.SetActiveScene()に置き換えます。
PUNの他の重要なクラスにはMonoBehaviourPunとMonoBehaviourPunCallbacksがあります。Fusionでは、NetworkBehaviourを継承するスクリプトにゲームロジックを記述したり状態を保持したりします。状態を保持しない場合、スクリプトはSimulationBehaviourを継承することもできます。スクリプトの初期化は、PUNではOnPhotonInstantiate()を呼び出していましたが、FusionではSpawned()コールバックを使用します。
PUNのカスタムプロパティはsetterメソッドを持つハッシュテーブルでしたが、Fusionはかわりに普通のC#のプロパティを同期します。NetworkBehaivourの[Networked]属性を付けた自動実装プロパティは、ゲームの状態の一部となります。オブジェクトの状態権限を持つプレイヤーのみが値を変更することが可能で、その値はネットワーク上で自動的に複製されるため、チートの影響が抑えられる側面もあります。
リモートプロシージャコール(RPC)もサポート済みで、より高水準になりました。メソッドに[Rpc]属性を付けてローカルのメソッドと同様に呼び出すと、Fusionはその呼び出しをネットワーク上で動作するように変換します。
対応表
| PUN | Fusion |
|---|---|
| PhotonNetwork | SimulationBehaviour.Runner and SimulationBehaviour.Object |
| MonoBehaviourPunCallbacks | SimulationBehaviour and NetworkBehaviour |
| PhotonNetwork.AddCallbackTarget(this) | N/A (automatic) |
| PhotonNetwork.Instantiate() | Runner.Spawn() |
| PhotonView | NetworkObject |
| IPunObservable.OnPhotonSerializeView() | C# auto-implemented properties and Input Sync |
| PhotonTransformView | NetworkTransform |
| PhotonRigidbodyView | NetworkRigidbody |
| PhotonAnimatorView | NetworkMecanimAnimator |
| N/A | NetworkCharacterController |
| [PunRPC] | [Rpc] |
| PhotonNetwork.LoadLevel() | Runner.SetActiveScene() |