This document is about: FUSION 2
SWITCH TO

Advanced Spawning

概述

在Fusion中的生成,包括調用Runner.Spawn()Runner.SpawnAsync()Runner.TrySpawn()。此調用建立了一個複製到所有其他同儕節點的網路實體。

  • 在伺服器/客戶端模式(伺服器/主機/單一)中,只有伺服器可以生成物件,並且該生成會複製到所有客戶端。
  • 在共享模式下,任何客戶端都可以調用Spawn(),但該調用會向共享伺服器生成一條訊息,然後共享伺服器會啟動實際的生成。

當調用或複製Spawn()時,會生成一個網路物件(一個帶有NetworkObject元件的Unity GameObject)作為回應。遊戲物件的生成方式由與NetworkRunner關聯的物件提供器確定。

物件提供器

物件提供器是一個INetworkObjectProvider實作,它定義了Runner.Spawn()Runner.Despawn()操作委任和解除Unity遊戲物件的管道。每個活躍中的NetworkRunner都有一個關聯的INetworkObjectProvider執行個體。預設下,這將是NetworkObjectProviderDefault執行個體。

自訂物件提供器使用

建立自己的自訂INetworkObjectProvider類別,可以精確控制生成的實際遊戲物件的生命週期,並且可以是有用的用例,例如;

  • 在運行階段動態建立網路物件
  • 進階處理單人玩家模式之間的遷移

指派物件提供器

有幾種方法可以為網路運行器設定物件提供器。

  • 調用Runner.GameStart()時傳遞INetworkObjectProvider的執行個體。

C#

runner.StartGame(new StartGameArgs(){ ObjectProvider = new MyObjectProvider()});
  • 或;向網路運行器遊戲物件新增一個實作INetworkObjectProvider的元件。
  • 或;兩者都不做,運行器將自動將NetworkObjectProviderDefault新增到其遊戲物件中。

INetworkObjectProvider實作

INetworkObjectProvider介面需要實作以下兩種方法:

  • AcquireInstance():用於在NetworkRunner.Spawn()已被調用時從池中取得物件。
  • ReleaseInstance():用於從NetworkRunner.Destroy()已被調用時從池中釋放與傳回物件。

網路物件提供器預設

NetworkObjectProviderDefaultINetworkObjectProvider的預設後援實作。如果您沒有在Runner.StartGame()中傳遞的StartArgs中指定提供器,運行器將在其遊戲物件中搜尋實作INetworkObjectProvider的元件。如果找不到實作,運行器將回退到自動向其遊戲物件新增NetworkObjectProviderDefault元件,然後將其用作物件提供器。

NetworkObjectProviderDefault是一個非常基本的實作,它將透過具現化已傳遞的預製件的副本來生成物件以回應Spawn(),而無需任何池。相反,Despawn()調用是用Destroy()處理的。

自訂池

物件池是一種常見的模式,用於最大限度地減少記憶體碎片化,並減輕CPU和垃圾收集器的負擔。

出於同樣的原因,儘管不是必需的,但建議在您的INetworkObjectProvider實作中實作NetworkObject的池化。

用於遊戲階段的物件池需要實作INetworkObjectPool。此外,在啟動它之前必須知道它,並將其指派給傳遞給NetworkRunner.StartGame()方法的StartGameArgs.ObjectPool參數。如果沒有指定物件池,則將使用NetworkObjectPoolDefault

在運行階段提供自訂物件

為了在運行階段動態生成遊戲物件(而不是使用預製件生成),您需要建立一個自訂INetworkObjectProvider類別,並覆寫AcquirePrefabInstance()方法以:

  1. 使用Instantiate()new GameObject()GameObject.CreatePrimitive()建立遊戲物件。
  2. 如果遊戲物件上不存在NetworkObject元件,請新增一個。
  3. 新增任何所需的下層GameObjectsNetworkBehaviours
  4. NetworkObjectBaker.Bake()網路物件(必須在對網路物件結構進行所有更改後最後完成)。
  5. 傳回NetworkObject執行個體作為結果。

在製作您自己的自訂INetworkObjectProvider實作時,可以(在大多數情況下建議)使用NetworkObjectProviderDefault作為基礎類別。

重要: 一旦生成並附加,網路物件就不能新增或刪除網路行為。生成之前,必須對網路物件上的網路行為進行任何自訂化。當然,仍然可以隨時新增或刪除任何非網路元件。

自訂物件提供器示例

此示例程式碼展示了在運行階段建立自訂網路物件,作為使用預製的預製件生成的替代方案。

C#

public class BakingObjectProvider : NetworkObjectProviderDefault
{
  // For this sample, we are using very high flag values to indicate custom.
  // Other values will fall through the default instantiation handling.
  public const int CUSTOM_PREFAB_FLAG = 100000;

  // The NetworkObjectBaker class can be reused and is Runner independent.
  private static NetworkObjectBaker _baker;
  private static NetworkObjectBaker Baker => _baker ??= new NetworkObjectBaker();

  public override NetworkObjectAcquireResult AcquirePrefabInstance(NetworkRunner runner, in NetworkPrefabAcquireContext context, out NetworkObject result)
  {
    // Detect if this is a custom spawn by its high prefabID value we are passing.
    // The Spawn call will need to pass this value instead of a prefab.
    if (context.PrefabId.RawValue == CUSTOM_PREFAB_FLAG)
    {
      var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
      var no = go.AddComponent<NetworkObject>();
      go.AddComponent<NetworkTransform>();
      go.name = $"Custom Object";

      // Baking is required for the NetworkObject to be valid for spawning.
      Baker.Bake(go);

      // Move the object to the applicable Runner Scene/PhysicsScene/DontDestroyOnLoad
      // These implementations exist in the INetworkSceneManager assigned to the runner.
      if (context.DontDestroyOnLoad)
      {
        runner.MakeDontDestroyOnLoad(go);
      }  
      else
      {
        runner.MoveToRunnerScene(go);
      }

      // We are finished. Return the NetworkObject and report success.
      result = no;
      return NetworkObjectAcquireResult.Success;        
    }

    // For all other spawns, use the default spawning.
    return base.AcquirePrefabInstance(runner, context, out result);
  }
}
Back to top