零基礎也能玩轉!跟我學,用 Sync Relay 與 Netcode 輕松開發流暢的聯機游戲!
在本篇文章中,我們將通過一個示例項目工程,展示在 Unity 編輯器中 如何使用Unity Online Services(UOS)提供的 Sync Relay 服務結合 Netcode for GameObjects 開發框架來實現高效、穩定的聯機游戲所需的房間管理功能和數據同步機制。
本教程中涉及 UOS 服務包括:
游戲數據同步服務 Sync Relay:用于實現游戲房間管理、實時數據同步等網絡通信功能
游戲數據同步服務 Sync
UOS Sync 服務是由 Unity 資深團隊打造的數據同步服務,為您提供一站式、高并發、低延遲、可靠的游戲同步解決方案,以滿足游戲在數據同步方面的嚴苛需求 。通過優化游戲數據流通的每一個環節,可確保數據的實時性、準確性和安全性,從而不僅能夠幫助開發者提升游戲品質與用戶體驗,還能在激烈的市場競爭中為游戲產品贏得更多的優勢與機遇。
以下是UOS Sync 服務的主要特點:
1、多元化傳輸協議支持,靈活應對不同場景:UOS Sync 服務支持主流傳輸協議,如 KCP(可靠 UDP 傳輸協議),WebSocket,UTP(Unity Transport Protocol,專為 Unity 游戲優化的網絡傳輸協議)等。這一多元化支持策略,允許不同客戶端根據網絡環境、設備性能以及游戲需求,采用最適合的傳輸協議進行高效同步,從而確保了游戲數據的實時性、準確性和穩定性。
2、云原生部署,動態資源管理,高效節能: 依托于先進的容器化云原生技術,UOS Sync 服務實現了資源的動態縮擴容與即開即用。這意味著服務能夠根據游戲實時負載情況,自動調整計算資源與存儲資源,確保在高并發場景下依然能夠保持高性能與低延遲。
3. 無縫集成主流游戲開發框架,加速游戲上線: UOS Sync 服務深度兼容并支持使 用 Mirror、Netcode 或 FishNet 等主流游戲開發框架開發的游戲項目。通過提供無縫接入的支持,UOS Sync 極大地簡化了游戲接入的流程與復雜度,使得開發者無需對原有游戲架構進行大規模改造或重構,即可輕松享受到 UOS Sync 帶來的高性能數據同步服務。
UOS Sync 服務模式分為:實時模式(Realtime)和中繼模式(Relay)兩種。
中繼模式(Sync Relay)
Sync Relay 模式的游戲服務邏輯會在某個房主玩家的機器上,會節約云上算力資源,但依賴房主的網絡環境。Relay 服務負責每個玩家與房主間的通信,它支持 Netcode,Mirror,FishNet 等開發框架。
實時模式(Sync Realtime)
Sync Realtime 模式是輕量級消息轉發服務,支持客戶端之間的信息同步,比如一對一、一對多、多對多。游戲邏輯的處理發生在每個玩家的客戶端。Realtime 模式適用于更新頻率低、處理邏輯輕量的游戲。
在本教程中,我們主要來學習 Sync Relay 模式結合 Netcode資源包在項目中的具體用法!
教程視頻
教程學習大綱
創建項目工程,并安裝 UOS Launcher
創建 UOS App,啟用 Sync-Relay 服務并安裝 SDK
安裝 Netcode for GameObjects 資源包,并導入項目示例資源包
設置 NetworkManager 和 RelayTransport 組件的參數
以 Host/Client 的模式運行游戲,進行測試游戲數據的同步
在 UOS 網頁端查看房間性能情況
用戶自定義創建新的房間配置
多人聯機服務選型參考指南
教程示例程序
教程內學習用到的項目素材資源,是通過在UOS Launcher窗口中直接在線安裝的。大家也可以通過下面提供的鏈接查看 Sync-Relay SDK 的示例程序。
Sync-Relay SDK代碼倉庫的地址:
https://unitychina.coding.net/public/uos/SyncRelaySDK/git/files/master/Samples~/SyncRelayNetcodeDemo
教程操作步驟
接下來讓我們跟著教程步驟開始學習吧!
1. 創建項目工程,并安裝 UOS Launcher
1.1 創建項目工程
打開 Unity hub,新建一個項目工程。選擇電腦上已經安裝過的 Unity 編輯器版本,自定義設置項目的名稱、工程的創建路徑。
1.2 安裝 UOS Launcher
在 Unity Editor 菜單欄中打開「Window -> Package Manager」,點擊左上角的「+」,選擇「Add package from git URL」;
然后輸入UOS Launcher 的 git 地址,點擊「Add」等待安裝完成。
https://e.coding.net/unitychina/uos/UOSLauncher.git
注意:該步驟要求當前環境已安裝 git,且 UOS Launcher 兼容的最低 Unity 版為 2021.3(LTS)。
2.創建 UOS App ,啟用 Sync-Relay 服務并安裝 Sync-Relay SDK
2.1創建 UOS App ,并與 Unity 項目工程進行關聯
接著前往 UOS 官網 ( https://uos.unity.cn ),創建一個 UOS 應用。選擇一個創建好的組織,輸入項目的名字,點擊「創建并啟用」。
在「設置」頁面,找到 UOS App 的信息并復制。
然后回到 Unity 編輯器中,點擊菜單欄「UOS -> Open Launcher」。在 UOS 面板中填寫復制好的 AppID/AppSecret/AppServiceSecret,并點擊「Link App」,實現與 UOS APP 進行關聯。
2.2 開啟 Sync-Relay 服務,并安裝Sync-RelaySDK開啟 Sync - Relay 服務
在編輯器內 Unity Online Services 窗口的下拉服務列表中,找到 Sync - Relay,點擊 Enable 按鈕來開啟服務。
開啟 Sync - Relay 服務后,網頁端進來看到默認已經創建好了一個房間配置。
參數含義解釋:
房間配置的超時時長——指一個房間從創建到關閉的最長存續時間,無論房間內是否有玩家,在到期時房間都會自動關閉,默認顯示是 30 分鐘。
空房間的超時時長——指一個房間在沒有玩家的狀態下最長存續的時間,默認顯示是 300 秒。房間在超過設定的時間內沒有玩家進入,房間會自動關閉。設置為 0 時,表示不檢查空房間超時。
點擊 Sync - Relay 服務旁邊的「Install SDK」的按鈕 ,就可以將 Sync - Relay 服務的 SDK 安裝到當前項目中。
安裝好 Sync - Relay SDK 以后,可以在 Package Manager 頁面中看到。
3.安裝 Netcode for GameObjects 資源包,并導入項目示例資源包3.1 安裝Netcode for GameObjects 資源包
接下來讓我們在項目內,安裝與聯網相關的資源包(Netcode for GameObjects)。
安裝方式一:
通過 Window → Package Manager → Unity Registry, 然后找到Netcode for GameObjects資源包 ,直接點擊「Install」。
安裝方式二:
通過打開 Window → Package Manager 窗口,點擊「+」-> Add package by name,填寫 name: com.unity.netcode.gameobjects,自行選擇輸入要安裝的版本號 version: 比如輸入 1.3.1,然后點擊「Add」添加。
溫馨提醒:這里推薦大家安裝1.3.1以上的 Netcode for GameObjects 版本。
3.2導入項目案例 Sample 包,打開 Sample 場景
在 UOS Launcher 中點擊「import sample」按鈕,即可導入項目示例工程資源包。
導入資源包后,在 Assets/Samples/UOS Sync Relay/1.1.1/Sync Relay Netcode Demo/Scenes/SampleScene.unity 路徑下(其中路徑中的 1.1.1 指的是安裝的 UOS Sync Relay SDK 的版本號),可以看到示例的 SampleScene 場景并打開。
在彈出的窗口中,點擊「Import TMP Essentials」來導入TextMeshPro 的字體資源。
4.設置 NetworkManager 和 RelayTransport(Netcode) 組件的參數
接下來就給大家講解下,場景中的游戲對象在項目中需要進行的設置啦!
4.1NetworkManager 組件的參數設置
NetworkManager 在整個游戲中必須有且只有一個, 它作為整個網絡的核心對網絡進行全局管理。
在場景中一般會新建一個空物體并給它添加組件NetworkManager.cs 的。 當前項目中的 NetworkManager 組件上的兩個重要參數PlayerPrefab 和 Network Transport已經設置好,如下圖紅框中所示:
如果是自己新創建的游戲對象添加的組件,需要自己來設置這兩個參數。我們需要設置Network Transport參數(它是用于網絡通信和數據傳輸的工具)。找到面板上的 Select transport 參數那里,點擊選擇 RelayTransportNetcode,選擇后 Unity 會自動為其加上對應的 RelayTransport 組件的。
4.2設置 Relay Transport 組件的房間配置 ID 號
從 UOS 網頁端 Sync Relay 的「配置」一欄,找到「房間配置 ID」號并復制。
將復制的「房間配置 ID」號粘貼到 Relay Transport(Netcode).cs 組件的Room Profile UUID 變量那里。
4.3設置 Player Prefab 參數
再來給大家講解一下 Player Prefab 這個參數, 它的作用是:當客戶端加入游戲時,系統會為該客戶端生成一個 Player Prefab 中綁定的游戲對象。
參數 Player Prefab 這里已經選擇好了 PlayerCube 這個預制物體對象。 預制物體已經添加 好 Network Object 和 Network Rigidbody 組件,還添加好了實現其移動和旋轉控制的數據同步的 PlayerMovement 腳本。
Network Object 組件:每個具有網絡行為的物體都必須添加一個 Network Object 組件,該組件的作用是為當前物體生成一個在網絡中唯一的 id,方便區別于其它物體。
Network Rigidbody 組件:來實現 通過網絡同步剛體的速度和其它屬性。
4.4場景中的小球對象GrabbableBallShared場景中的小球對象,也添加好了網絡相關的組件 Network Object 和 Network Transform。
Network Transform:它的作用是將玩家的信息從服務器端同步到客戶端。如果我們想要同步位置會進行動態改變的物體,那么就要添加 Network Transform 組件。
4.5場景中的可縮放 Scale 的 Cube 對象
場景中有兩個會循環縮放 Scale 的 Cube 對象,網絡同步的組件已經添加好了。而且 Cube 上掛載了腳本組件 ScalingCube.cs,可以實現縮放 Scale 的效果。
腳本中的以下示例代碼:展示了使用 Repeat 函數實現了 Cube 對象的 x 軸方向的大小重復縮放。
using Unity.Netcode;
using UnityEngine;
public class ScalingCube : MonoBehaviour
{
private void Update()
{
if (NetworkManager.Singleton == null || !NetworkManager.Singleton.IsServer)
{
return;
}
transform.localScale = new Vector3(Mathf.Repeat(Time.time * 2, 3f), transform.localScale.y, transform.localScale.z);
}
}
4.6 界面 UI 元素
再來解析下場景中的界面 UI 元素!在 Canvas 下面創建了 5 個 Button 對象。
ExitButton 按鈕—— 掛載了 ExitButtonScript.cs 腳本,實現當點擊退出按鈕時,切換到索引為 0 的第一個場景。
public void OnExitScene()
{
if (NetworkManager.Singleton)
{
NetworkManager.Singleton.Shutdown();
Destroy(NetworkManager.Singleton.gameObject);
}
if (m_SceneMenuToLoad != null && m_SceneMenuToLoad.GetReferencedScenes()[0] != string.Empty)
{
SceneManager.LoadSceneAsync(m_SceneMenuToLoad.GetReferencedScenes()[0], LoadSceneMode.Single);
}
else
{
SceneManager.LoadSceneAsync(0, LoadSceneMode.Single);
}
}
? ButtonsRoot 下面的按鈕,都已經對應綁定了 ConnectionModeScript.cs 腳本中的方法。比如:
CreateHost 按鈕綁定了 OnStartHostButton 方法
Join Game as Client 按鈕綁定了 OnStartClientButton 方法
5.以 Host/Client 的模式運行游戲,進行測試游戲數據的同步
我們可以選擇一個在編輯器中 Play 模式下測試,另一個提前 Build 成 exe文件。然后以Host/Client 的模式運行游戲。
5.1 構建 Build 文件
將當前場景添加到File → BuildSettings列表中,即可點擊【Build】按鈕,生成一個可執行文件。 如果有需要,可以在Edit → Project Settings頁面,點擊Player 按鈕,自定義設置修改要導出的 exe 文件的窗口的大小。
例如:這里選擇窗口模式【Windowed】,分辨率設置為 1280 * 720 像素大小。
5.2查看代碼的初始化首先分析代碼的初始化信息,我們需要在創建或加入房間之前,設置好玩家信息,以及需要配置好各個狀態下的回調函數可以查看下 ConnectionModeScript.cs 腳本中的代碼:
private void Start()
{
//此處省略其它代碼......
if (UseUSync())
{
//需要在創建或者加入房間之前,設置好玩家信息
uid = Guid.NewGuid().ToString();
var props = new Dictionary
(); props.Add("icon", "unity"); NetworkManager.Singleton.GetComponent ().SetPlayerData(uid, "Player-" + uid, props); //需要在創建或者加入房間之前,配置好回調函數 var callbacks = new RelayCallbacks(); callbacks.RegisterConnectToRelayServer(OnConnectToRelayServer);//當連接到 Relay 服務器 callbacks.RegisterPlayerEnterRoom(OnPlayerEnterRoom);//當有玩家加入房間 callbacks.RegisterPlayerLeaveRoom(OnPlayerLeaveRoom);//當有玩家離開房間 callbacks.RegisterMasterClientMigrate(OnMasterClientMigrate);//在退出房間或掉線時會觸發 callbacks.RegisterSetHeartbeat(OnSetHeartBeat);//設置心跳超時時間 NetworkManager.Singleton.GetComponent ().SetCallbacks(callbacks); } }
?然后我們在項目中采用 Netcode for GameObjects 的Host/Client 的模式來進行測試。
5.3在編輯器中點擊 Create Host 的按鈕
在編輯器中點擊Create Host的按鈕 ,由于當前編輯器既是作為服務器又是作為客戶端啟動的,所以會克隆生成一個之前設置好的 PlayerCube 預制物體對象。
由于預制體對象已經提前綁定好了 PlayerMovement.cs 腳本,所以可以通過W/S按鍵實現前后移動物體,A/D按鍵實現左右旋轉物體 。
房主加進來以后,此時在 Console 控制臺,可以看到房間的狀態更新為(Ready)已就緒的狀態 了。
5.4 異步創建房間的代碼
以 Host 身份加入游戲,會創建一個房間。此時 查看 ConnectionModeScript.cs 腳本中的 OnStartHostButton 方法,看到在異步創建房間的代碼中,設置了房間的名稱、命名空間、最大連接的玩家數等信息。
public void OnStartHostButton()
{
if (NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && m_ConnectionModeButtons)
{
if (UseUSync())
{
StartCoroutine(LobbyService.AsyncCreateRoom(new CreateRoomRequest()
{
Name = "Demo",
Namespace = "Unity",
MaxPlayers = 20,
Visibility = LobbyRoomVisibility.Public,
OwnerId = uid,
CustomProperties = new Dictionary
() { {"a", "b"}, } }, ( resp) => { if (resp.Code == (uint)RelayCode.OK) { Debug.Log("Create Room succeed."); if (resp.Status == LobbyRoomStatus.ServerAllocated) { NetworkManager.Singleton.GetComponent ().SetRoomData(resp); StartHost(); } else { Debug.Log("Room Status Exception : " + resp.Status.ToString()); } } else { Debug.Log("Create Room Fail By Lobby Service"); } })); } else { StartHost(); } } }
此時在 UOS 網頁端,點擊刷新的按鈕,可以看到頁面上顯示的房間的名稱 Demo、命名空間 Unity 等信息,和腳本中都是一致的,而且當前房間的狀態也是【已就緒】的狀態 。
5.5 在客戶端可執行文件中點擊 Join Game as Client
打開客戶端可執行 exe 文件, 點擊Join Game as Client,以客戶端的身份加入游戲中。
此時會發現又再次克隆出來了一個預制物體對象,而且我們也可以通過 WSAD 按鍵控制 exe 文件中的 Capsule 對象。同時 發現兩個窗口中的兩個 Capsule 對象的位置、旋轉角度的數據都是一樣的,說明我們已經實現游戲對象的網絡同步了。
作為客戶端加入后,在 Console 控制臺窗口,也能看到打印輸出的日志信息,顯示有玩家加入了房間。
此時在作為 Host 的編輯器的 Hierarchy 窗口,可以看到創建出來了兩個名字為 PlayerCube(Clone) 的對象。
5.6 獲取大廳房間列表的方法
當有玩家以client的身份加入房間時 ,會執行 OnStartClientButton 方法。在該方法中會異步查詢房間列表,找到狀態為 Ready 的一個房間加入。
public void OnStartClientButton()//以 client 身份加入游戲
{
if (NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && m_ConnectionModeButtons)
{
if (UseUSync())
{
StartCoroutine(LobbyService.AsyncListRoom(new ListRoomRequest()
{
Namespace = "Unity",
Start = 0,
Count = 10,
}, ( resp) =>
{
if (resp.Code == (uint)RelayCode.OK)
{
Debug.Log("List Room succeed.");
if (resp.Items.Count > 0)
{
foreach (var item in resp.Items)
{
if (item.Status == LobbyRoomStatus.Ready)
{
StartCoroutine(LobbyService.AsyncQueryRoom(item.RoomUuid,
( _resp) =>
{
if (_resp.Code == (uint)RelayCode.OK)
{
Debug.Log("Query Room succeed.");
NetworkManager.Singleton.GetComponent ()
.SetRoomData(_resp);
StartClient();
}
else
{
Debug.Log("Query Room Fail By Lobby Service");
}
}));
break;
}
}
}
}
else
{
Debug.Log("List Room Fail By Lobby Service");
}
}));
}
else
{
StartClient();
}
}
}
5.7 修改Relay Transport 組件的屬性信息
接下來讓我們再看看,如何在腳本中修改 Relay Transport 組件的屬性信息吧!
按下U 鍵
在編輯器的 Inspector 窗口,可以看到默認的心跳超時時長為 15 秒。
當按下 U 按鍵后,可以看到心跳超時時長參數被修改為了 30 秒。
可以切換到 PlayerMovement.cs 腳本,查看代碼中 SetHeartbeat 方法的調用。下面的示例代碼也給大家展示了如何修改玩家的信息(調用 UpdatePlayerInfo 方法)、更改房間的自定義屬性信息(調用 UpdateRoomCustomProperties 方法)等功能。
if (Input.GetKeyDown(KeyCode.U))
{
Debug.Log("PRESS U");
NetworkManager.Singleton.GetComponent ().SetHeartbeat( 30, null);
/*
var p = NetworkManager.Singleton.GetComponent ().GetCurrentPlayer();
p.Name = "Update";
p.Properties.Add("newicon", "u3d");
NetworkManager.Singleton.GetComponent ().UpdatePlayerInfo(p);
*/
var p = new Dictionary
(); p.Add("f", "x"); p.Add("b", "z"); NetworkManager.Singleton.GetComponent ().UpdateRoomCustomProperties(p); }
? 按下 U 鍵運行后,在 Console 控制臺窗口,也可以看到對應輸出的日志信息。
按下R 鍵
下面的代碼實現了按下 R 鍵時,會遍歷輸出當前的房間的自定義的屬性信息。
if (Input.GetKeyDown(KeyCode.R))
{
Debug.Log("PRESS R");
var r = NetworkManager.Singleton.GetComponent ().GetRoomInfo();
Debug.LogFormat("Properties Count : {0}", r.CustomProperties.Count);
foreach (var item in r.CustomProperties)
{
Debug.LogFormat("Property {0} - {1}", item.Key, item.Value);
// var items = item.Value.Properties.Select(kvp => kvp.ToString());
// Debug.Log(string.Join(", ", items));
}
}
? 當在編輯器中按下 R 鍵后,回到 Console 控制臺窗口,已經輸出了對應的日志信息了。
5.8 斷開網絡傳輸后,房間會被回收
此時如果在編輯器中按下 K 鍵,會斷開客戶端和服務端之間的連接,我們發現場景中只有一個 Capsule 游戲對象了。
日志信息會顯示,有客戶端玩家 Player 離開了房間。
此時在編輯器中停止運行游戲后,可以看到日志信息提示-已經關閉了網絡傳輸。
最后等所有的客戶端都離開房間之后,根據設定的【空房間時長】,時間到了之后房間的狀態會切換到【已回收】狀態。
空房間的超時時長(秒)——指一個房間在沒有玩家的狀態下最長存續的時間,默認顯示是 300 秒。房間在超過設定的時間內沒有玩家進入,房間會自動關閉。 設置為 0 時,表示不檢查空房間超時。
在特殊情況下,也可以點擊 UOS 頁面上的按鈕,手動強制關閉房間。
6.在 UOS 網頁端查看房間性能情況查看房間性能
為充分利用計算資源,Sync 服務會在一個 Pod 內創建多個房間。我們點擊「房間管理」頁面的「查看性能」按鈕,可以查看服務器的性能監控情況。
可以看到 CPU、內存、網絡使用率情況,房間規模越大性能越好,開發者可以根據自己的游戲情況選擇房間大小。
大家可以進入 UOS 網頁端了解更多關于性能測試的用法: https://uos.unity.cn/doc/sync/perf7.用戶自定義創建新的房間配置
大家可以 在Sync Relay 的「配置」頁面,根據游戲房間的規模、存在時長、負載與性能,選擇房間模板并創建自己的房間配置。點擊「創建房間配置」按鈕,自己創建一個房間配置如下圖所示,自行選擇微型、小型還是中型的房間規模。
房間配置的超時時長——指一個房間從創建到關閉的最長存續時間,無論房間內是否有玩家,在到期時房間都會自動關閉,默認顯示是 30 分鐘。
空房間的超時時長——指一個房間在沒有玩家的狀態下最長存續的時間,默認顯示是300 秒。房間在超過設定的時間內沒有玩家進入,房間會自動關閉。設置為 0 時,表示不檢查空房間超時。
此時在 UOS 網頁端可以看到新創建的房間配置 sync-room-profile。如果創建了有多個房間配置的話,可以復制一下自己要使用的那個房間配置的 ID 號。
然后在 Unity 編輯器的項目工程內, 找到RelayTransport(Netcode) 組件,將剛才復制的房間配置 ID 號粘貼到Room Profile UUID 參數那里。
8.多人聯機服務選型參考指南
如果你對多人聯機游戲技術架構選型存在困惑的話,可以前往 UOS 網頁端查看多人聯機服務選型參考指南,也可以通過 UOS 的公眾號文章來查看詳情。
UOS 網頁端鏈接:
https://uos.unity.cn/product/multiplayer
UOS 公眾號文章:
如果你要追求服務器的絕對穩定的話,建議用 Netcode for GameObjects 開發完成后,Build 成Dedicated Server,然后使用UOS Multiverse進行托管。
學習途徑
UOS 配套的相關學習教程視頻也已同步上傳至 Unity 中文課堂和 B 站,搜索 “使用Sync Relay & Netcode輕松構建聯機游戲數據同步指南”即可找到,歡迎大家前往學習,UOS 更多學習教程持續更新中,敬請期待!
了解更多 UOS 相關信息:
官網:https://uos.unity.cn
技術交流 QQ 群:823878269
公眾號:UOS 游戲云服務
Unity 官方微信
第一時間了解Unity引擎動向,學習進階開發技能
每一個“在看”,都是我們前進的動力
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.