概述 Netcode for GameObjects 是 Unity 官方推出的多人游戏网络库,取代了旧版的 UNET(已废弃)。它基于 客户端-服务器 (Client-Server)模型——一个权威服务器处理所有关键逻辑,客户端负责输入和渲染。
本篇覆盖 Netcode 的核心概念:NetworkObject、NetworkVariable、RPC、客户端-服务器同步、玩家权限控制。
1. 核心概念 1.1 客户端-服务器模型 1 2 3 4 5 6 7 8 9 10 11 服务器(权威): ├── 验证玩家输入 ├── 更新游戏状态 ├── 同步到所有客户端 └── 处理延迟补偿 客户端(非权威): ├── 收集玩家输入 ├── 发送给服务器 ├── 接收服务器状态 └── 渲染画面
1.2 安装 1 Package Manager -> Unity Registry -> Netcode for GameObjects
2. NetworkObject 与 NetworkVariable 2.1 NetworkObject 任何需要网络同步的 GameObject 必须附加 NetworkObject 组件:
1 2 3 4 5 6 7 8 9 10 11 using Unity.Netcode;public class Bullet : NetworkBehaviour { [ServerRpc ] private void SpawnBulletServerRpc (Vector3 origin, Vector3 direction ) { var bullet = Instantiate(bulletPrefab, origin, Quaternion.LookRotation(direction)); bullet.GetComponent<NetworkObject>().Spawn(); } }
2.2 NetworkVariable 自动同步的状态变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class PlayerHealth : NetworkBehaviour { public NetworkVariable<int > Health = new (100 , NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); public NetworkVariable<bool > IsDead = new (false , NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); private void Awake () { Health.OnValueChanged += OnHealthChanged; } private void OnHealthChanged (int oldValue, int newValue ) { UpdateHealthUI(newValue); } [ServerRpc ] public void TakeDamageServerRpc (int damage ) { if (IsDead.Value) return ; Health.Value -= damage; if (Health.Value <= 0 ) { Health.Value = 0 ; IsDead.Value = true ; } } }
3. RPC 调用 3.1 ServerRpc(客户端 -> 服务器) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class PlayerController : NetworkBehaviour { [ServerRpc ] private void SubmitInputServerRpc (Vector3 movement, bool jump ) { transform.position += movement * Time.deltaTime * _moveSpeed; } private void Update () { if (!IsOwner) return ; var move = new Vector3(Input.GetAxis("Horizontal" ), 0 , Input.GetAxis("Vertical" )); if (move != Vector3.zero) SubmitInputServerRpc(move, Input.GetButtonDown("Jump" )); } }
3.2 ClientRpc(服务器 -> 客户端) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class GameManager : NetworkBehaviour { [ClientRpc ] private void ShowExplosionClientRpc (Vector3 position, float radius ) { Instantiate(_explosionPrefab, position, Quaternion.identity); } [ClientRpc(RequireOwnership = false) ] private void UpdateScoreClientRpc (int playerId, int newScore ) { ScoreUI.Instance.UpdatePlayerScore(playerId, newScore); } }
4. 玩家管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class GameManager : NetworkBehaviour { [SerializeField ] private GameObject _playerPrefab; public override void OnNetworkSpawn () { NetworkManager.Singleton.OnClientConnectedCallback += OnPlayerConnected; NetworkManager.Singleton.OnClientDisconnectCallback += OnPlayerDisconnected; } private void OnPlayerConnected (ulong clientId ) { if (!IsServer) return ; var spawnPos = new Vector3(Random.Range(-10f , 10f ), 0 , Random.Range(-10f , 10f )); var player = Instantiate(_playerPrefab, spawnPos, Quaternion.identity); var networkPlayer = player.GetComponent<NetworkObject>(); networkPlayer.SpawnAsPlayerObject(clientId); } private void OnPlayerDisconnected (ulong clientId ) { if (!IsServer) return ; if (NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var client)) { client.PlayerObject?.Despawn(); } } }
5. 网络位置同步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class NetworkTransform : NetworkBehaviour { private NetworkVariable<Vector3> _networkPosition = new (); [SerializeField ] private float _lerpSpeed = 10f ; private void Update () { if (IsOwner) { if (IsServer) _networkPosition.Value = transform.position; } else { transform.position = Vector3.Lerp( transform.position, _networkPosition.Value, Time.deltaTime * _lerpSpeed); } } }
6. 测试与调试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class NetworkTester : MonoBehaviour { private void OnGUI () { if (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer) { if (GUILayout.Button("Host (Server + Client)" )) NetworkManager.Singleton.StartHost(); if (GUILayout.Button("Client" )) NetworkManager.Singleton.StartClient(); } } }
总结
NetworkBehaviour 替代 MonoBehaviour,启用网络功能
NetworkVariable 自动同步状态,服务器写入、客户端读取
ServerRpc 客户端到服务器,ClientRpc 服务器到客户端
NetworkObject.Spawn() 在服务器上生成网络对象
位置同步需要插值处理,减少网络延迟影响
下一篇将搭建 多人游戏架构实战 ,包括房间系统、同步策略和网络性能优化。