このページは編集中です。更新が保留になっている可能性があります。

スポーニング

はじめに

GameObjectがネットワーク上に存在するためには、以下の条件を満たす必要があります。

  1. NetworkObjectコンポーネントを持っていること。
  2. Runner.Spawn()メソッドを使って作成されること。

NetworkObjectは、Fusionがネットワーク全体で一意の識別子を割り当てるために使用されます。これにより、すべてのクライアントがそれぞれのインスタンスかを認識し、ネットワーク上の各オブジェクトの状態を正しく同期させることができます。Runner.Spawn()メソッドは、いつ、どのようにして新しいオブジェクトのインスタンスをネットワーク全体の状態に追加するかをFusionに伝えます。

トップに戻る

重要!

Unityに内蔵されているGameObject.Instantiate()GameObject.Destroy()メソッドをネットワークオブジェクトに使用しないでください。ネットワーク状態が壊れたまま、Fusionシミュレーションループから完全に切り離されたローカルゲームオブジェクトが作成されてしまいます。

トップに戻る

Runner.Spawn

FusionのNetworkRunnerインスタンスのRunner.Spawn()メソッドは、UnityのGameObject.Instantiate()メソッドを模倣しています。メソッドに与えることのできるパラメータは以下の通りです。

  1. NetworkObject タイプのプレハブ。
  2. 位置
  3. 回転
  4. オブジェクトの入力権限を持つクライアントを識別するためのPlayerRef
  5. オブジェクトを他のインスタンスに複製する前に実行される、NetworkRunner.OnBeforeSpawned型のデリゲート。
  6. 予測されたスポーンである場合には、NetworkObjectPredictionKey型の予測キー。

プレハブのみが必須のパラメータで、他はすべて任意です。

var obj = Runner.Spawn(prefab, Vector3.zero, Quaternion.identity, Runner.LocalPlayer, MyOnBeforeSpawnDelegate, key);

どのクライアントでもRunner.Spawn()を呼び出すことができますが、ネットワークトポロジーによって結果は異なります。

  • サーバーでは、ホスト型またはクライアント/サーバー型のモードでは、生成されたオブジェクトの所有権(State Authority)がサーバーに割り当てられ、オブジェクトが作成されてすぐに返されます。クライアントは、次のスナップショットの一部としてオブジェクトを受け取ります。
  • ホスト型モードまたはクライアント/サーバーモードのクライアントでは、デフォルトでは何も起こらず、コールはnullを返します。しかし、Fusionでは、一時的なローカルオブジェクトを作成して即座にフィードバックすることができます。これは「予測スポーン」と呼ばれます。
  • 共有モードでは、 State Authorityは常に呼び出し側に割り当てられ、インスタンスはすぐに返されます。他のクライアントは、いずれオブジェクトを受け取ります。

いずれの場合も、SpawnはFixedUpdateNetworkから呼び出すべきで、ForwardとRe-simulationの両方のステージで呼び出すことができます。Fusionでは、予測されたローカル・スポーンの再シミュレーションの際に、同じオブジェクトを正確に返します(予測キーが一致していることが前提です)。一方、権威あるスポーンは共有モードかホスト上でのみ発生し、どちらも再シミュレーションを行いません。

いずれの場合も、SpawnはFixedUpdateNetworkから呼び出されるべきで、ForwardとRe-simulationの両方のステージで呼び出すことができます。Fusionでは、予測されたローカルスポーンの再シミュレーションの際に、同じオブジェクトを正しく返します(予測キーが一致していることが前提です)。一方、権威あるスポーンは共有モードかホスト上でのみ発生し、どちらも再シミュレーションを行いません。

トップに戻る

入力権限

入力権限は、特定のクライアントの PlayerRef をメソッドに渡すことで割り当てられます(これは任意です)。入力権限を与えられたクライアントは、オブジェクトの入力データを提供することができ、(ホストやサーバーに加えて)GetInput()でその入力構造を照会することができます。

オブジェクトが入力を必要としない場合や、入力権限を持つクライアントがいない場合は、代わりに null を渡すことができます。

トップに戻る

OnBeforeSpawned

NetworkRunner.OnBeforeSpawnedパラメータには、デリゲートのシグネチャに一致するメソッドまたはラムダ式を指定できます。

public delegate void OnBeforeSpawned(NetworkRunner runner, NetworkObject obj);

このデリゲートは、オブジェクトが作成された後、すべてのインスタンスで同期される前に呼び出されます。これにより、システムの他の部分がオブジェクトにアクセスできるようになる前に、呼び出し側がオブジェクトのカスタム初期化を追加で行うことができます。カスタムのネットワークプロパティを初期化するのに適した場所です。

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);
}

トップに戻る

Spawned

Fusionが新しいオブジェクトを作成すると、そのオブジェクトのSpawned()メソッドが呼び出されます。Spawned()コールバックは、ネットワークに接続されていない変数やサブシステムをリセットするためのものです。例えば、アプリケーションがオブジェクトプーリングを使用している場合、オブジェクトがリサイクルされてデフォルトの状態ではなくなったため、Spawned()は値をプレハブのデフォルトにリセットする必要があります。すべての NetworkBehaviour コンポーネントは ISpawned インターフェースを実装しており、NetworkBehaviour から派生したすべてのコンポーネントは、このインターフェースをオーバーライドして実装することができます。ただし、SimulationBehaviour 由来のコンポーネントは、Spawned() メソッドを呼び出すために、ISpawned とそのメソッドを明示的に実装する必要があります。

Spawned()は、Fusionがオブジェクトの存在を初めて認識したときに呼び出されます。これは、権威あるピアがオブジェクトを最初に生成したときのティックとは一致しませんし、必ずしも同じティックの近くではありません。このため、Networked の状態を Spawned() で初期化したり、RPCSpawned() で送信するべきではありません。

  • State Authorityを持つピアでのスポーンでは、Runner.Spawn()の直後にSpawned()が呼ばれます。
  • 入力権限を持つピア上の予測されたスポーンの場合、Spawned()はネットワークの状態が割り当てられたとき(つまり、スポーンが確認されたとき)に呼び出されます。
  • プロキシ(ピアが入力権限も状態権限も持っていないオブジェクト)の場合、ローカルに存在しないオブジェクトのネットワーク状態をFusionが受け取ると、Spawned()が呼ばれます。特に、後から参加したプレイヤーはだいぶ前に生成されたオブジェクトを受け取る可能性が高く、そのオブジェクトの "birth tick "の元の状態は関係ありません。

スポーン時に状態を初期化する必要がある場合は、Runner.Spawn()に供給されるスポーン前のNetworkRunner.OnBeforeSpawnedコールバックを使用します。

トップに戻る

Despawn

ネットワークオブジェクトを削除するには、そのオブジェクトのState Authorityを持つピアが、Runner.Despawn()を呼び出します。

トップに戻る

Despawned

ISpawned を実装したクラスに対して、Runner.Spawn()Spawned() メソッドの呼び出しを引き起こすのと同様に、Despawn()は、IDespawned() を実装したクラスに対してIDespawned() メソッドの呼び出しを引き起こします。

すべてのNetworkBehaviourIDespawnedを実装していますが、SimulationBehaviourは明示的に追加する必要があります。

トップに戻る

スポーン予想

Spawn Prediction is only available in Host / Server Mode

Predictive Spawningは、権限を持たないクライアントが将来のオブジェクトの存在を予測し、ネットワーク上でオブジェクトの存在が成功または失敗したと確認されるまで、ローカルのプレースホルダーをシミュレートすることができます。

この機能を実現するためには2つのことが必要です。

  1. クライアントが一時的なローカルオブジェクトと将来の「実際の」インスタンスと一致するためには、一意の識別子を作成する必要があります。これにより、スポーンが確認されたときに、ローカルオブジェクトをファーストクラスのネットワークオブジェクトにアップグレードすることができます。
  2. クライアントは、ローカルオブジェクトが確認またはキャンセルされるまで、そのまま処理する必要があります。

トップに戻る

NetworkObjectPredictionKey

Runner.Spawn()メソッドのpredictionKeyパラメータは4バイトで構成されています。アプリケーションは、以下の点を考慮する限り、独自のキーを自由に作成することができます。

  1. キーは、クライアントと権威あるホスト/サーバで同じでなければなりません。ランダムにしたり、ローカルデータに基づいたりすることはできません。 2.プレイヤーと現在のティックに対して一意である必要があります。 ティック(またはその下端部分)とプレーヤーIDをキーに含めるのが賢明です。
var predictionKey = new NetworkObjectPredictionKey {Byte0 = (byte) Runner.Simulation.Tick, Byte1 = playerIndex};

注意: 同一ティック内に複数のネットワークオブジェクトがクライアントによって予測的に生成された場合、生成された様々なNetworkObjectsを見分けるための追加情報(例えば、共有カウンター)が必要となります。

トップに戻る

IPredictedSpawnBehaviour

スポーンされたゲームオブジェクトが予測状態にある間は、Fusionシミュレーションの一部ではなく、ネットワーク化されたプロパティは、アクセスできる状態がまだないので機能しません。予測されたオブジェクトを実際のオブジェクトのように動作させるためには、いくつかの追加ロジックが必要です。このロジックは、IPredictedSpawnBehaviourインターフェースを使って実装します。

public interface IPredictedSpawnBehaviour {
    void PredictedSpawnSpawned();
    void PredictedSpawnUpdate();
    void PredictedSpawnRender();
    void PredictedSpawnFailed();
    void PredictedSpawnSuccess();
  }

トップに戻る

Spawned, Update, Render

最初の3つのメソッドは、機能的な SimulationBehaviour および NetworkBehaviour コンポーネントにある Spawned(), FixedUpdateNetwork() および Render() メソッドに一致します。これらのメソッドは、これらのメソッドと同じ条件で呼び出されます。ただし、これらのメソッドは、オブジェクトが「予測」された状態にあるときに、排他的かつ明示的に呼び出されるという違いがあります。

これらのメソッドの実装としては、単純にそれぞれSpawned()FixedUpdateNetwork()Render()を呼び出すことができますが、アプリケーションはネットワークプロパティが利用できないことを考慮する必要があります。これに対する1つの解決策は、ネットワーク化されたプロパティを予測スポーンのチェックでラップし、次のように2セットの変数を維持することです。

[Networked]
public Vector3 networkedVelocity { get; set; }
private Vector3 _predictedVelocity;
public Vector3 velocity
{
    get => Object.IsPredictedSpawn ? _predictedVelocity : networkedVelocity;
    set
    {
      if (Object.IsPredictedSpawn)
        _predictedVelocity = value;
      else
        networkedVelocity = value;
    }    
}

トップに戻る

Failed と Success

PredictedSpawnFailed()PredictedSpawnSuccessは予測に特有のもので、サーバーやホストがスポーンアクションの成功または失敗を確認したときにトリガーされます。予測が成功した場合は PredictedSpawnSuccess() が呼ばれ、そうでない場合は PredictedSpawnFailed() が発生します。

一時オブジェクトは完全にネットワーク化されたオブジェクトにプロモートされ、何も変更されていないかのように存在し続けるため、アプリケーションが正常なスポーンを処理する必要はほとんどありません。 ただし、予測の失敗は処理する必要があります。 最も簡単な実装は、オブジェクトを破棄することです。

予測されたオブジェクトでRunner.Dispawn() を使用する際には、問題のオブジェクトが予測された状態であったことを示すために、追加のブールパラメータが必要です。

public void PredictedSpawnFailed()
{
    Runner.Despawn(Object, true);
}

Runner.Spawn()はFusion Object Poolを介して一時オブジェクトを取得し、それを再びプールに戻す必要があるため、 Runner.Despawn()を使用する必要があります。

ドキュメントのトップへ戻る