スポーン(基礎)
はじめに
ネットワークオブジェクトは、通常のGameObject.Instantiate()
でインスタンス化するかわりに、スポーンする必要があります。
実行時にネットワークオブジェクトをスポーンするには、Runner.Spawn()
メソッドを使用します。シーンオブジェクトは、シーンがロードされた時に自動的にスポーンされるため、明示的にスポーンする必要はありません。
FusionはNetworkObject
にネットワーク間でユニークなIDを割り当てるため、すべてのクライアントはネットワークオブジェクトの各インスタンスを識別できて、それらの状態を正しく同期できるようになります。Runner.Spawn()
メソッドによって、いつどのようにして新しいオブジェクトのインスタンスをネットワーク上の状態の集合に追加するかをFusionに伝えます。
重要!
ネットワークオブジェクトに対して、UnityのGameObject.Instantiate()
メソッドを使用しないでください。ゲームオブジェクトはローカルでのみ生成されるため、Fusionのシミュレーションループからは完全に切り離され、ネットワーク上の状態を壊してしまいます。
Runner.Spawn
FusionのNetworkRunner
インスタンスのRunner.Spawn()
メソッドは、UnityのGameObject.Instantiate()
メソッドに似ています。メソッドに与えられるパラメーターは以下の通りです。
NetworkObject
型のプレハブ- 位置(position)
- 回転(rotation)
- オブジェクトに対して入力権限を持たせたいクライアントの
PlayerRef
(ホストモードでのみ関係します) - オブジェクトを複製する前に実行される
NetworkRunner.OnBeforeSpawned
型のデリゲート
必須パラメーターはプレハブのみで、それ以外は任意のオプションです。
備考: Spawn
メソッドで渡した位置と回転は、メソッドを実行したピアのオブジェクトのtransform
にのみ影響します。この位置と回転を他のピアに反映させるには、NetworkTransform
・NetworkTRSP
を継承したコンポーネント・transform
を同期する完全に独自のコンポーネントのいずれかが必要です。
C#
var obj = Runner.Spawn(prefab, Vector3.zero, Quaternion.identity, Runner.LocalPlayer, MyOnBeforeSpawnDelegate);
Runner.Spawn()
はどのクライアントからでも呼び出すことができますが、その結果はネットワークトポロジーによって異なります。
- ホストモードでは、ホスト/サーバーのみがネットワークオブジェクトをスポーンできます。クライアント側でスポーンを実行したい場合、ホスト/サーバーにリクエストを(RPCなどで)送る必要があります。
- 共有モードでは、すべてのクライアントがネットワークオブジェクトをスポーンできます。ネットワークオブジェクトをスポーンすると、状態権限は自動的にそのクライアントへ割り当てられます。
Input Authority
メソッドに特定のクライアントのPlayerRef
を渡すと、そのクライアントに入力権限が割り当てられます。これは任意のオプションです。入力権限を持つクライアントは、オブジェクトに対して入力データを与えることができるようになり、(入力権限を持つクライアントと、ホスト/サーバーは)GetInput()
からその入力構造体を取得できます。
オブジェクトが入力を必要としない、または入力権限を持つクライアントがいない場合は、null
を渡します。
OnBeforeSpawned
NetworkRunner.OnBeforeSpawned
パラメーターには、シグネチャが一致するメソッドかラムダ式を渡すことができます。
C#
public delegate void OnBeforeSpawned(NetworkRunner runner, NetworkObject obj);
このデリゲートは、オブジェクトが生成された後かつ、オブジェクトがすべてのクライアント間で同期される前に呼び出されます。これによって、オブジェクトが他のシステムからアクセス可能になる前に、呼び出し側でオブジェクトに対する初期化処理を追加できるようになります。ここはネットワークプロパティの初期化に適した場所です。
C#
private void MySpawnFunction(){
Runner.Spawn(
_objPrefab,
Vector3.zero,
Quaternion.identity,
inputAuthority: null,
InitializeObjBeforeSpawn,
predictionKey: null
);
}
private void InitializeObjBeforeSpawn(NetworkRunner runner, NetworkObject obj)
{
var objSB = obj.GetComponent<ObjSimulationBehaviour>();
objSB.InitializeObjSettings(_currentExplosionForce);
}
多くのパラメーターを渡すことができるラムダ式を使用することも可能です。
C#
private void MySpawnFunction(){
Runner.Spawn(
_objPrefab,
Vector3.zero,
Quaternion.identity,
inputAuthority: null,
(Runner, NO) => NO.GetComponent<MyCustomBehaviour>().Init(myInt, myParameter)
predictionKey: null
);
}
Spawned
ISpawned.Spawned()
は、NetworkRunner
がNetworkObject
を紐づけた(NetworkRunner.Spawn()
呼び出しの結果、またはNetworkObject
を含むシーンのロード)直後に呼び出されます。Spawned()
コールバックは、FusionにおけるAwake()
の代替とみなすことができ、「有効な」オブジェクトが「紐付けられた」後にのみ呼び出されます。
NetworkBehaviour
はISpawned
インターフェースを実装していて、Spawned()
は空の仮想メソッドになっています。独自のNetworkBehaviour
でSpawned()
を実装するには、単にSpawned()
をオーバーライドしてください。
状態権限者がSpawned()
で行うすべてのネットワークプロパティの更新は、他すべてのピア上でスポーンしたNetworkObject
インスタンスの初期値となります。しかしリモートのピアは、(関心領域、インタレストマネジメント、途中参加、優先順位などの理由で)常に状態権限者と同じティックにオブジェクトがスポーンするとは限りません。リモートのNetworkObject
が状態権限者より後のティックでスポーンした場合、そのティックに状態権限者が保持している値を初期値としてスポーンすることになります。
- 状態権限を持つピアでのスポーンは、
Runner.Spawn()
直後にSpawned()
が呼び出されます - 状態権限を持たないピアでは、
NetworkRunner
がネットワーク上の状態を受信した際に、ローカルに存在しないNetworkObject
がスポーンします
NetworkRunner
に紐付けられるより前にNetworkObject
を初期化したい場合は、Runner.Spawn()
から渡せるOnBeforeSpawnedコールバックを使用してください。
IAfterSpawned
IAfterSpawned.AfterSpawned()
は、一連のNetworkObject
がスポーンして、すべてのISpawned.Spawned()
コールバックが完了した後に呼び出されます。これは、FusionにおけるStart()
の代替と考えることができます。スポーン後のNetworkBehaviour
で、実行順序を気にせずに別のNetworkBehaviour
の値を取得/設定する必要がある場合に、このコールバックを使用してください。
Despawn
ネットワークオブジェクトを削除するには、オブジェクトの状態権限を持つピアでRunner.Despawn()
を呼び出してください。
Despawned
Runner.Spawn()
によって、NetworkBehaviour
のようなISpawned
を実装したクラスでSpawned()
メソッドが呼び出されるのと同じように、Despawn()
によって、IDespawned
を実装したクラスでDespawned()
メソッドが呼び出されます。