如何在Unity+NetCode多人游戏中为所有客户端创建全局变量?
Unity NetCode 全局共享变量实现方案
要实现所有客户端、主机/服务器共用的变量,NetworkVariable是NetCode官方推荐的方案,它会自动处理变量同步,包括新客户端连接时的初始同步。下面是具体实现步骤和代码示例:
一、核心实现:用NetworkVariable同步共享变量
1. 创建全局管理器脚本
新建一个继承自NetworkBehaviour的脚本,挂载到带有NetworkObject组件的GameObject上(这个对象将作为全局状态管理器):
using Unity.Netcode; using UnityEngine; public class GlobalGameState : NetworkBehaviour { // 定义共享字符串:所有人可读,仅服务器可写 public NetworkVariable<string> SharedGameString = new NetworkVariable<string>( defaultValue: "初始共享内容", readPerm: NetworkVariableReadPermission.Everyone, writePerm: NetworkVariableWritePermission.Server); // 客户端调用此ServerRpc请求修改共享变量 [ServerRpc(RequireOwnership = false)] public void UpdateSharedStringServerRpc(string newContent) { // 服务器端修改变量,自动同步到所有客户端 SharedGameString.Value = newContent; } // 可选:监听变量变化(所有客户端/服务器都会触发) private void Awake() { SharedGameString.OnValueChanged += OnStringUpdated; } private void OnStringUpdated(string oldVal, string newVal) { Debug.Log($"共享字符串更新:{oldVal} → {newVal}"); } }
2. 配置全局管理器对象
- 创建空GameObject,添加
NetworkObject组件 - 将上面的
GlobalGameState脚本挂载到该对象上 - 在
NetworkManager的Spawn Prefabs列表中添加这个对象(如果是场景内对象,勾选NetworkObject的「Scene Object」选项,并确保场景被NetworkManager加载)
3. 客户端读取/修改变量的方式
- 读取:客户端直接访问
SharedGameString.Value即可拿到最新值(新客户端连接时会自动同步当前值) - 修改:客户端不能直接修改
SharedGameString.Value(因为写权限是服务器),必须调用UpdateSharedStringServerRpc("新内容"),由服务器完成修改并同步到所有客户端
二、为什么之前的尝试可能失败?
- 没有将脚本挂载到
NetworkObject上:NetworkVariable必须依附于NetworkBehaviour,而NetworkBehaviour必须在NetworkObject对象上才能生效 - 权限设置错误:如果给了客户端写权限,会导致多端修改冲突;正确的做法是服务器独占写权限,客户端通过ServerRpc请求修改
- 直接修改客户端侧的NetworkVariable值:客户端没有写权限时,修改的值不会同步到服务器和其他客户端,仅本地有效
三、备选方案:用ServerRpc/ClientRpc手动同步
如果需要更自定义的同步逻辑,可以手动用Rpc实现,但需要处理新客户端的初始同步:
using Unity.Netcode; using UnityEngine; public class GlobalGameState : NetworkBehaviour { private string sharedString = "初始内容"; // 客户端请求修改 [ServerRpc(RequireOwnership = false)] public void UpdateStringServerRpc(string newVal) { sharedString = newVal; // 通知所有客户端更新 SyncStringToClientsClientRpc(newVal); } // 服务器同步给所有客户端 [ClientRpc] private void SyncStringToClientsClientRpc(string newVal) { sharedString = newVal; Debug.Log($"收到同步:{newVal}"); } // 新客户端连接时主动请求初始值 public override void OnNetworkSpawn() { if (IsClient && !IsServer) { RequestInitialStringServerRpc(); } } [ServerRpc(RequireOwnership = false)] private void RequestInitialStringServerRpc() { // 仅给请求的客户端发送当前值 SendInitialStringClientRpc(sharedString, NetworkManager.Singleton.LocalClientId); } [ClientRpc] private void SendInitialStringClientRpc(string currentVal, ulong targetClientId) { if (NetworkManager.Singleton.LocalClientId == targetClientId) { sharedString = currentVal; Debug.Log($"获取初始值:{currentVal}"); } } }
这种方式需要手动处理新客户端的初始同步,不如NetworkVariable省心,优先推荐第一种方案。
内容的提问来源于stack exchange,提问作者Happy_cat
相关产品推荐
相关产品推荐

