This page is a work in progress and could be pending updates.

Quickstart

快速入門

您剛剛創建了一個新的Unity項目,導入了Fusion SDK,現在想開始編寫您的下一個多人遊戲;或者,您有一個現有的單人遊戲原型。無論哪種情況,您該從哪裡開始呢?

建議您從其中一個樣本開始。它們將為您提供多人遊戲的最佳實踐和設計模式的直接實現,其中許多可以直接複製到您自己的制作項目中。

但在您開始編碼之前,這份文件解釋了大多數基本組件,並指出了它們的作用,這樣您就會知道一旦您深入研究實際的樣本代碼時應該注意什麼。

Back To Top

基礎知識

您將使用的兩個主要Fusion組件是NetworkRunnerNetworkObjectNetworkRunner可以被認為是Fusion的核心-在您的場景中只有一個,它將管理網路和模擬。這發生在伺服器和客戶端。

NetworkObject添加到一個普通的Unity預制件或場景對象中,將在執行時給它分配一個網路身份,並讓它成為基於tick的同步模擬的一部分。它還可以讓您配置一些選項(例如,使這個特定的對象總是數據傳輸的一部分-全局對象)。

另外兩個基本行為可以被繼承,並為遊戲對象添加實際網路。仿真行為(SimulationBehaviour)和網路行為(NetworkBehaviour)。

網路屬性(包括遊戲狀態)將被添加到NetworkBehaviourSimulationBehaviour的專門子類),而後者可用於控制模擬步驟和回調,而不攜帶網路屬性。

NetworkBehaviour應該被用來保存在網路上自動同步的數據。為了定義一個網路狀態值,只需創建一個屬性並將其標記為[Networked],例如:

[Networked] public byte life { get; set; }

[Networked]適用於所有原始類型(除了bool,您應該使用NetworkBool,因為它將被正確地序列化為一個位元)。它也適用於結構和對其他NetworkObject的引用(甚至是預制板),因為這些可以在所有客戶端上安全地識別。

重要: Fusion將用訪問實際網路狀態數據的代碼替換空的get/set存根,所以這些存根應保持空。

註冊一個呼叫返回也很容易,在每次聯網屬性值發生變化時都會被觸發:

[Networked(OnChanged = "OnTypeChanged")] public Type type { get; set; }

public static void OnTypeChanged(Changed<TheClassWhichHasTheProperty> changed)
{
  // 您的代碼在這裡 - 查看API文檔了解更多細節
}

In addition to the actual callback name, you can also control where the callback is executed:

  • OnChangedLocal (true/false) - 設置為true,事件鉤就會在改變屬性的機器上被呼叫,例如伺服器(默認為false)。
  • OnChangedRemote (true/false) - 設置為false,只在改變屬性的機器上呼叫事件鉤(默認為true)

Back To Top

內置網路行為

Fusion提供了各種預設的NetworkBehaviour,以使遊戲或原型快速啟動和執行。

NetworkTransform保持一個物體轉換的同步(也可以包含碰撞器)。通過最先進的快照插值,自動保持平滑。通過直接改變Unity的Transform上的數據,也可以直接做完整的客戶端預測(在任何遊戲客戶端)。

對於物理學控制的剛體,推薦使用NetworkRigidbody。同樣的插值選項也能起作用,Fusion只需設置一個配置選項,就可以直接用PhysX做完全的預測/滾動。

對於由玩家直接控制的物體,如人形角色,Fusion有一個內置的NetworkCharacterController。對於更復雜的用例,可以重新使用基本的靜態查詢(提供表面切線、穿透力修正等),並與您的自定義代碼相匹配,進行轉向/移動。

Back To Top

基於Tick的呼叫返回

為了編寫遊戲模擬代碼,SimulationBehaviour的循環開始發揮作用。仍然可以使用Unity內置的Awake()Start()等,但一般來說,我們更推薦使用網路安全的對應物:

Fusion的Start()的對應物被稱為Spawned(),當該對象在特定的機器(伺服器或客戶端)上第一次被啟動時,它就被觸發。使用Awake()對那些在對象生命周期內不會改變的東西進行一次性初始化 - 對GetComponent<>()的呼叫經常屬於這一類,但一般來說,在您通常使用Start()的地方使用Spawned()

Fusion最重要的呼叫返回是FixedUpdateNetwork()FixedUpdateNetwork()是Fusion用來執行下一個網路狀態的邏輯,並在對賬期間重新模擬。

在API文檔中對所有這些呼叫返回都有詳細的描述,但您需要了解的重要部分是,FixedUpdateNetwork(),像FixedUpdate()一樣,是以固定的時間間隔呼叫的,這與渲染率無關。而且,與FixedUpdate()不同的是,當重新模擬來調節來自伺服器的更新時,它可以為同一個狀態/幀/點多次呼叫。

對於網路屬性來說,resimulation是透明的,因為Fusion在呼叫FixedUpdateNetwork()之前會隱含地重置所有網路狀態屬性。

例如,從FixedUpdateNetwork()中執行類似的項目是完全安全的,只要有關對象使用NetworkTransform或其他內置組件之一:

transform.position += transform.forward * Runner.DeltaTime;

注意Runner.DeltaTime的使用,這是保持模擬與網路tick 頻率一致的必要條件。

Render()保証在所有呼叫FixedUpdateNetwork()之後和LateUpdate()之前執行。

Back To Top

輸入

Fusion將輸入處理分成兩個獨立的步驟:

  1. 從本地硬件收集輸入並將其放入一個結構中。這總是只在客戶端和主機上進行(而不是在專用伺服器上),每次新的勾選都要進行一次。這將被發送到伺服器,同時也用於本地的即時客戶端預測(在客戶端)。
  2. FixedUpdateNetwork()可以讀取這個輸入,以改變遊戲狀態(推進模擬)。這可以在客戶端(從任何有輸入權限的網路對象)和主機/伺服器上進行。在客戶機上,這可以在同一時間段內多次發生,以便在調和滾動時重新模擬。

第一步可以被認為是一個常規的Unity輸入處理機制,它簡單地記錄玩家正在做什麼,並存儲起來供以後使用,而第二步是一個耦合腳本,應用該輸入來修改網路狀態。

第一步由Fusion在其OnGetInput()呼叫返回中輪詢,第二步由FixedUpdateNetwork()中呼叫GetInput()TryGetInput()來處理,通常由您的主角的SimulationBehaviour負責。

Back To Top

Remote Procedure Calls

雖然輸入結構和使用[Networked]屬性應該是您保持網路客戶端之間遊戲狀態同步的首選方法(並保持伺服器權限),但有時這根本不是最實用的解決方案。

例如,當一個客戶端想與一個它沒有輸入權限的對象進行罕見的復雜交互時:比如用您庫存中的特定鑰匙來打開一扇鎖著的門。

我們可以在輸入結構中加入一些字段,告訴伺服器使用哪把鑰匙和哪扇門,但這種方法很快就會在輸入結構中產生大量很少使用的雜亂無章的東西。

另一件需要考慮的事情是,常規的Fusion輸入並不可靠-數據包可能會丟失。如果您正在做某種形式的連續輸入,比如移動一個角色,這很少會被注意到,但如果您正在做一個單一的一次性動作,您可能想確保它到達伺服器。

對於這些情況,Fusion支持RPCs(遠端過程呼叫)。

Fusion為RPCs實現了一個簡單而強大的語法。要在任何 SimulationBehaviour上定義一個RPC,您要聲明一個常規的C#方法,其返回類型為; void,並給它加上"[Rpc]"屬性。它可以接受任何原始參數(除了bool,見上文)以及結構和對Fusion對象的引用(例如NetworkObjectPlayerRef-任何有網路身份的項目)。

[Rpc]屬性允許您過濾它可能被呼叫和它被執行的地方:

[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color)
{
    playerName = name;
    playerColor = color;
}

還要注意 "RPC "前綴的使用-雖然您不必使用這個確切的符號,但您必須在方法名前或後綴上 "rpc"(不區分大小寫)。

除了源頭和目標屬性外,[Rpc]屬性還有一些額外的可選參數:

  • Channel (Reliable/Unreliable) - 如果您不關心RPC在傳輸過程中的丟失,則設置為Unreliable (默認為Reliable)
  • InvokeLocal (true/false) - 如果您不想在本地客戶端呼叫RPC,設置為false (默認為true)
  • InvokeResim (true/false) - 如果您想在重新模擬時也呼叫RPC,設置為true(默認為false)。

關於RPC的最後一點是,您應該記住RPC沒有明確的狀態-即使您向 "所有客戶 "發送,尚未在線的客戶也不會收到它,而跳出又回到的客戶會忘記它曾經發生過。出於這個原因,您應該始終確保RPC的狀態是真正的瞬時的(例如聊天訊息),或者它的效果被間接記錄在[Networked]屬性中。


To Document Top