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()已被調用時從池中釋放與傳回物件。
網路物件提供器預設
NetworkObjectProviderDefault是INetworkObjectProvider的預設後援實作。如果您沒有在Runner.StartGame()中傳遞的StartArgs中指定提供器,運行器將在其遊戲物件中搜尋實作INetworkObjectProvider的元件。如果找不到實作,運行器將回退到自動向其遊戲物件新增NetworkObjectProviderDefault元件,然後將其用作物件提供器。
NetworkObjectProviderDefault是一個非常基本的實作,它將透過具現化已傳遞的預製件的副本來生成物件以回應Spawn(),而無需任何池。相反,Despawn()調用是用Destroy()處理的。
自訂池
物件池是一種常見的模式,用於最大限度地減少記憶體碎片化,並減輕CPU和垃圾收集器的負擔。
出於同樣的原因,儘管不是必需的,但建議在您的INetworkObjectProvider實作中實作NetworkObject的池化。
用於遊戲階段的物件池需要實作INetworkObjectPool。此外,在啟動它之前必須知道它,並將其指派給傳遞給NetworkRunner.StartGame()方法的StartGameArgs.ObjectPool參數。如果沒有指定物件池,則將使用NetworkObjectPoolDefault。
在運行階段提供自訂物件
為了在運行階段動態生成遊戲物件(而不是使用預製件生成),您需要建立一個自訂INetworkObjectProvider類別,並覆寫AcquirePrefabInstance()方法以:
- 使用
Instantiate()、new GameObject()或GameObject.CreatePrimitive()建立遊戲物件。 - 如果遊戲物件上不存在
NetworkObject元件,請新增一個。 - 新增任何所需的下層
GameObjects和NetworkBehaviours。 NetworkObjectBaker.Bake()網路物件(必須在對網路物件結構進行所有更改後最後完成)。- 傳回
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