当前位置: 首页 > news >正文

Unity网络编程入门:掌握Netcode for GameObjects实现多人游戏基础(Day 39)

Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘

PyTorch系列文章目录

Python系列文章目录

C#系列文章目录

01-C#与游戏开发的初次见面:从零开始的Unity之旅
02-C#入门:从变量与数据类型开始你的游戏开发之旅
03-C#运算符与表达式:从入门到游戏伤害计算实践
04-从零开始学C#:用if-else和switch打造智能游戏逻辑
05-掌握C#循环:for、while、break与continue详解及游戏案例
06-玩转C#函数:参数、返回值与游戏中的攻击逻辑封装
07-Unity游戏开发入门:用C#控制游戏对象移动
08-C#面向对象编程基础:类的定义、属性与字段详解
09-C#封装与访问修饰符:保护数据安全的利器
10-如何用C#继承提升游戏开发效率?Enemy与Boss案例解析
11-C#多态性入门:从零到游戏开发实战
12-C#接口王者之路:从入门到Unity游戏开发实战 (IAttackable案例详解)
13-C#静态成员揭秘:共享数据与方法的利器
14-Unity 面向对象实战:掌握组件化设计与脚本通信,构建玩家敌人交互
15-C#入门 Day15:彻底搞懂数组!从基础到游戏子弹管理实战
16-C# List 从入门到实战:掌握动态数组,轻松管理游戏敌人列表 (含代码示例)
17-C# 字典 (Dictionary) 完全指南:从入门到游戏属性表实战 (Day 17)
18-C#游戏开发【第18天】 | 深入理解队列(Queue)与栈(Stack):从基础到任务队列实战
19-【C# 进阶】深入理解枚举 Flags 属性:游戏开发中多状态组合的利器
20-C#结构体(Struct)深度解析:轻量数据容器与游戏开发应用 (Day 20)
21-Unity数据持久化进阶:告别硬编码,用ScriptableObject优雅管理游戏配置!(Day 21)
22-Unity C# 健壮性编程:告别崩溃!掌握异常处理与调试的 4 大核心技巧 (Day 22)
23-C#代码解耦利器:委托与事件(Delegate & Event)从入门到实践 (Day 23)
24-Unity脚本通信终极指南:从0到1精通UnityEvent与事件解耦(Day 24)
25-精通C# Lambda与LINQ:Unity数据处理效率提升10倍的秘诀! (Day 25)
26-# Unity C#进阶:掌握泛型编程,告别重复代码,编写优雅复用的通用组件!(Day26)
27-Unity协程从入门到精通:告别卡顿,用Coroutine优雅处理异步与时序任务 (Day 27)
28-搞定玩家控制!Unity输入系统、物理引擎、碰撞检测实战指南 (Day 28)
29-# Unity动画控制核心:Animator状态机与C#脚本实战指南 (Day 29)
30-Unity UI 从零到精通 (第30天): Canvas、布局与C#交互实战 (Day 30)
31-Unity性能优化利器:彻底搞懂对象池技术(附C#实现与源码解析)
32-Unity C#进阶:用状态模式与FSM优雅管理复杂敌人AI,告别Spaghetti Code!(Day32)
33-Unity游戏开发实战:从PlayerPrefs到JSON,精通游戏存档与加载机制(Day 33)
34-Unity C# 实战:从零开始为游戏添加背景音乐与音效 (AudioSource/AudioClip/AudioMixer 详解)(Day 34)
35-Unity 场景管理核心教程:从 LoadScene 到 Loading Screen 实战 (Day 35)
36-Unity设计模式实战:用单例和观察者模式优化你的游戏架构 (Day 36)
37-Unity性能优化实战:用Profiler揪出卡顿元凶 (CPU/GPU/内存/GC全面解析) (Day 37)
38-Unity C# 与 Shader 交互入门:脚本动态控制材质与视觉效果 (含 MaterialPropertyBlock 详解)(Day 38)
39-Unity网络编程入门:掌握Netcode for GameObjects实现多人游戏基础(Day 39)


文章目录

  • Langchain系列文章目录
  • PyTorch系列文章目录
  • Python系列文章目录
  • C#系列文章目录
  • 前言
  • 一、网络游戏架构基础
    • 1.1 客户端/服务器 (C/S) 架构
      • 1.1.1 C/S 架构定义与特点
      • 1.1.2 C/S 架构工作流程
      • 1.1.3 C/S 适用场景
    • 1.2 点对点 (P2P) 架构
      • 1.2.1 P2P 架构定义与特点
      • 1.2.2 P2P 架构挑战
      • 1.2.3 P2P 适用场景
    • 1.3 C/S vs. P2P 对比总结
  • 二、网络同步核心概念
    • 2.1 什么是网络同步?
    • 2.2 状态同步 (State Synchronization)
      • 2.2.1 原理与机制
      • 2.2.2 优缺点分析
      • 2.2.3 应用场景
    • 2.3 远程过程调用 (RPC - Remote Procedure Call)
      • 2.3.1 原理与机制
      • 2.3.2 优缺点分析
      • 2.3.3 应用场景
    • 2.4 状态同步与 RPC 的关系
  • 三、Unity Netcode for GameObjects 入门
    • 3.1 Netcode for GameObjects 简介
    • 3.2 核心组件概览
      • 3.2.1 NetworkManager
      • 3.2.2 NetworkObject
      • 3.2.3 NetworkBehaviour
    • 3.3 关键网络概念实现
      • 3.3.1 NetworkVariable\<T\>
      • 3.3.2 ServerRpc
      • 3.3.3 ClientRpc
  • 四、实践:搭建基础网络同步场景
    • 4.1 准备工作
      • 4.1.1 安装 Netcode 包
      • 4.1.2 创建基础场景
    • 4.2 配置 NetworkManager
    • 4.3 创建玩家同步脚本
      • 4.3.1 创建 PlayerController 脚本
      • 4.3.2 添加 NetworkObject 组件
      • 4.3.3 实现位置同步 (使用 NetworkTransform)
      • 4.3.4 实现基本移动逻辑
    • 4.4 添加 NetworkTransform 组件
    • 4.5 测试场景
      • 4.5.1 构建与运行
      • 4.5.2 观察同步效果
  • 五、常见问题与进阶思考
    • 5.1 延迟 (Latency) 问题
    • 5.2 NAT 穿透
    • 5.3 安全性考量
    • 5.4 下一步学习
  • 六、总结


前言

欢迎来到【Unity C# 学习之旅】的第 40 天!经过前几周对 C# 基础、面向对象、数据结构以及 Unity 核心机制的学习,我们已经具备了开发复杂单机游戏的能力。然而,现代游戏的一个重要趋势是多人在线互动。今天,我们将正式踏入网络编程的世界,了解多人游戏背后的基本原理,并重点学习 Unity 官方推荐的网络解决方案——Netcode for GameObjects,最终动手实现一个简单的玩家位置同步功能。无论你是网络编程新手,还是想了解 Unity 最新网络技术的开发者,本文都将为你提供一个清晰的起点。

一、网络游戏架构基础

在开始编写网络代码之前,理解多人游戏底层的通信模式至关重要。主要有两种基础架构:客户端/服务器(C/S)和点对点(P2P)。

1.1 客户端/服务器 (C/S) 架构

1.1.1 C/S 架构定义与特点

C/S 架构是最常见的多人游戏网络模型。在这种模型中:

  • 服务器 (Server): 是一台(或一组)拥有游戏世界最终决定权的计算机。它负责处理所有核心游戏逻辑、验证玩家操作、维护游戏状态,并将状态同步给所有客户端。可以把它想象成一个餐馆的中央厨房,所有订单(玩家输入)都送到这里处理,然后由服务员(网络)将菜品(游戏状态)送达给顾客(客户端)。
  • 客户端 (Client): 是玩家运行游戏的设备。客户端负责接收玩家输入,将其发送给服务器,并接收来自服务器的游戏状态更新,最终渲染游戏画面。

特点:

  • 权威性 (Authority): 服务器是权威的,可以有效防止作弊(例如,客户端不能直接修改自己的生命值)。
  • 状态一致性: 由于服务器统一管理状态,更容易保证所有玩家看到的游戏世界是一致的。
  • 可扩展性: 服务器可以设计为支持大量玩家连接。
  • 缺点: 需要专门的服务器硬件和维护成本;所有通信都经过服务器,可能引入延迟;服务器是单点故障(如果服务器宕机,所有人都无法游戏)。

1.1.2 C/S 架构工作流程

一个典型的 C/S 交互流程如下:

Client A Server Client B 连接请求 连接确认 连接请求 连接确认 发送输入 (如移动 W 键) 处理输入, 更新游戏状态 (A 的位置) 同步最新状态 (包含 A 的新位置) 同步最新状态 (包含 A 的新位置) 渲染画面 (根据新状态) 渲染画面 (根据新状态) 发送输入 (如开火) 处理输入, 判定命中, 更新状态 同步状态 (B 开火, 可能 A 受伤) 同步状态 (B 开火效果) 渲染画面 渲染画面 loop [游戏进行中] Client A Server Client B

1.1.3 C/S 适用场景

绝大多数需要强一致性、反作弊要求高、玩家数量较多的在线游戏,如:

  • 大型多人在线角色扮演游戏 (MMORPG)
  • 多人在线战术竞技游戏 (MOBA)
  • 大多数第一人称射击游戏 (FPS)
  • 在线策略游戏 (RTS)

1.2 点对点 (P2P) 架构

1.2.1 P2P 架构定义与特点

P2P 架构中,玩家(节点)之间直接建立连接并交换数据,没有中心服务器负责核心游戏逻辑。每个客户端都可能运行一部分服务器逻辑,或者所有客户端共同维护游戏状态。可以把它想象成朋友之间直接打电话聊天,没有总机转接。

特点:

  • 低延迟: 数据直接在玩家间传输,理论上延迟较低(尤其在地理位置相近时)。
  • 无服务器成本: 不需要专门的服务器硬件。
  • 缺点:
    • 同步复杂: 保持所有客户端状态一致非常困难,容易出现不同步(Desync)。
    • 作弊风险高: 每个客户端都有一定的“权力”,更容易作弊。
    • NAT 穿透问题: 客户端之间直接建立连接可能因网络地址转换(NAT)而失败,通常需要“打洞”技术或中继服务器(Relay Server)辅助连接。
    • 主机迁移复杂: 如果作为“主机”的玩家掉线,需要复杂的机制来选择新的主机并恢复游戏状态。

1.2.2 P2P 架构挑战

P2P 主要面临同步一致性、安全性(作弊)以及网络连接建立(NAT 穿透)的挑战。现代 P2P 游戏通常采用一些混合策略或特定技术(如确定性锁步)来缓解这些问题。

1.2.3 P2P 适用场景

适用于玩家数量较少、对延迟要求极高、且能容忍一定同步风险或有特定技术解决同步问题的游戏,如:

  • 一些合作类游戏 (Co-op)
  • 格斗游戏(对低延迟要求极高)
  • 部分早期的 RTS 游戏

1.3 C/S vs. P2P 对比总结

特性客户端/服务器 (C/S)点对点 (P2P)
核心中央服务器处理逻辑和状态客户端之间直接通信,分散处理
权威性服务器权威,易于反作弊权威分散,作弊风险高
一致性容易保证状态一致同步复杂,易出现不一致
延迟取决于客户端到服务器的延迟理论上玩家间延迟较低
成本需要服务器硬件和维护成本无需专用服务器成本
连接客户端连接服务器客户端互连,需处理NAT穿透
扩展性较好通常受限于同步复杂性
适用场景MMO, MOBA, FPS, 大部分网游Co-op, 格斗游戏, 小规模对战

注意: 实践中也存在混合架构,例如使用服务器进行匹配和关键逻辑验证,而部分数据通过 P2P 传输。

二、网络同步核心概念

无论采用哪种架构,都需要解决的核心问题是:如何让不同机器上的游戏实例看起来是同一个游戏世界?这就是网络同步要解决的问题。主要有两种基本技术:状态同步和远程过程调用(RPC)。

2.1 什么是网络同步?

网络同步是指通过网络在多个游戏客户端(以及可能的服务器)之间传输数据,以维持一个共享的、看起来一致的游戏状态的过程。因为网络有延迟,数据不可能瞬间到达所有地方,所以需要各种技术来“隐藏”或“补偿”这种延迟,让玩家感觉游戏是实时互动的。

2.2 状态同步 (State Synchronization)

2.2.1 原理与机制

状态同步的核心思想是:定期将游戏中重要对象的状态(如位置、旋转、生命值、动画状态等)从一个权威源(通常是 C/S 架构中的服务器)发送给所有其他参与者(客户端)。客户端接收到这些状态更新后,调整本地对应的对象。

  • 权威源: 负责计算和维护“真实”状态。
  • 状态快照 (Snapshot): 权威源在特定时间点捕获关键对象的状态信息。
  • 网络传输: 将状态快照通过网络发送给其他客户端。
  • 客户端应用: 客户端接收快照,并更新本地游戏对象的状态。为了平滑过渡,通常会使用插值 (Interpolation)(在两个已知状态之间平滑移动)或外插 (Extrapolation) / 预测 (Prediction)(基于当前状态和速度预测未来状态)技术。

2.2.2 优缺点分析

  • 优点:
    • 能够保证最终的状态一致性(以权威源为准)。
    • 相对容易理解和实现基础版本。
  • 缺点:
    • 可能消耗较多带宽(尤其当对象多、状态复杂、同步频率高时)。
    • 对于接收方,状态更新总是有延迟的,可能导致看到的不是“最新”状态,需要插值/预测技术来改善体验。

2.2.3 应用场景

适用于需要持续同步的数据,例如:

  • 玩家和 NPC 的位置、旋转。
  • 载具的状态。
  • 玩家的生命值、弹药量等。
  • 游戏场景中动态对象的状态(如移动平台)。

2.3 远程过程调用 (RPC - Remote Procedure Call)

2.3.1 原理与机制

RPC 允许你在一台机器上调用另一台机器上的函数(方法)。就像你在本地调用一个函数一样,但这个函数实际上在远程执行。

  • 调用方 (Caller): 发起 RPC 请求的机器。
  • 被调用方 (Callee): 实际执行 RPC 函数的机器。
  • 网络传输: RPC 请求(包括函数名和参数)通过网络发送。
  • 远程执行: 被调用方接收请求,找到对应的函数并执行。

在游戏网络中,通常有:

  • 客户端到服务器 RPC (Client-to-Server RPC): 客户端请求服务器执行某个操作。例如,玩家按下开火键,客户端调用服务器上的 FireWeapon RPC。
  • 服务器到客户端 RPC (Server-to-Client RPC): 服务器命令一个或多个客户端执行某个操作。例如,服务器判定一个玩家死亡,调用该玩家客户端以及其他相关客户端上的 PlayerDied RPC 来播放死亡动画和音效。

2.3.2 优缺点分析

  • 优点:
    • 非常适合触发一次性的、离散的事件或动作。
    • 语义清晰,就像调用本地函数一样。
  • 缺点:
    • 过度使用 RPC 可能导致网络拥塞。
    • 需要小心处理 RPC 的执行顺序和可靠性(是否保证送达)。
    • 安全性考量:必须严格验证来自客户端的 RPC,防止作弊。

2.3.3 应用场景

适用于触发事件、发送命令等场景:

  • 玩家开火、施法、跳跃等动作的发起。
  • 发送聊天消息。
  • 通知客户端播放特效或音效。
  • 同步非持续性的状态改变(如门的开关)。

2.4 状态同步与 RPC 的关系

状态同步和 RPC 通常是协同工作的。

  • 状态同步负责维护那些持续变化需要保持精确一致的数据(如位置)。
  • RPC负责处理那些瞬间发生的事件或动作(如开火、使用技能)。

例如,玩家移动时,使用状态同步持续更新位置;当玩家按下跳跃键时,客户端发送一个 RequestJump RPC 给服务器,服务器验证后(比如检查玩家是否在地面上),再通过状态同步(更新 Y 轴位置和跳跃状态)或另一个 RPC(通知其他客户端播放跳跃动画)来同步跳跃效果。

三、Unity Netcode for GameObjects 入门

Unity 提供了多种网络解决方案,Netcode for GameObjects 是 Unity 官方目前主推的、用于 GameObject/MonoBehaviour 工作流的网络库。它旨在简化网络游戏的开发,并集成了许多底层的网络概念。

3.1 Netcode for GameObjects 简介

Netcode for GameObjects (简称 Netcode) 提供了一套相对高级的 API,让开发者可以基于熟悉的 Unity 组件化思想来构建网络功能。它主要面向 C/S 架构(虽然也支持 Host 模式,即一个玩家同时是 Server 和 Client),并内置了状态同步和 RPC 的实现机制。

3.2 核心组件概览

使用 Netcode 时,你会接触到几个核心组件:

3.2.1 NetworkManager

这是 Netcode 的核心控制器和配置中心。通常在场景中放置一个带有 NetworkManager 组件的 GameObject。它负责:

  • 连接管理: 启动服务器 (StartServer)、主机 (StartHost) 或客户端 (StartClient)。
  • 网络传输层 (Transport): 配置底层的数据传输方式(默认使用 Unity Transport,基于 UDP)。
  • 玩家对象管理: 指定用于代表玩家的 Prefab,并在玩家连接时自动生成。
  • 网络对象生成/销毁: 管理场景中网络对象的同步生成与销毁。
  • 场景管理: 同步场景加载。

3.2.2 NetworkObject

要让一个 GameObject 能够在网络上被识别和同步,它必须附加 NetworkObject 组件。这个组件赋予 GameObject 一个唯一的网络 ID (NetworkObjectId),使得服务器和所有客户端都能引用到同一个“逻辑”对象,即使它们是本地场景中的不同实例。

3.2.3 NetworkBehaviour

这是一个特殊的 MonoBehaviour,你需要让所有包含网络逻辑(状态同步变量、RPC 方法)的脚本都继承自 NetworkBehaviour 而不是 MonoBehaviourNetworkBehaviour 提供了访问网络状态(如 IsOwner, IsServer, IsClient)和调用网络功能(RPC、同步变量)的能力。

3.3 关键网络概念实现

Netcode 提供了具体的类和特性来实现状态同步和 RPC:

3.3.1 NetworkVariable<T>

这是 Netcode 实现状态同步的主要方式。NetworkVariable<T> 是一个泛型结构体,可以包装几乎任何可序列化的数据类型(如 int, float, Vector3, string, 自定义 struct 等)。

  • 声明:NetworkBehaviour 脚本中声明一个 NetworkVariable
    public NetworkVariable<int> PlayerHealth = new NetworkVariable<int>();
    public NetworkVariable<Vector3> PlayerPosition = new NetworkVariable<Vector3>();
    
  • 权限设置: 默认情况下,只有服务器可以修改 NetworkVariable 的值。可以通过构造函数参数设置读写权限。
  • 自动同步: 当服务器上的 NetworkVariable 的值发生改变时,Netcode 会自动将这个新值同步给所有客户端。
  • 值变更通知: 可以在客户端或服务器上订阅 OnValueChanged 事件,以便在值发生变化时执行特定逻辑(如更新 UI)。

3.3.2 ServerRpc

用于实现客户端调用服务器方法的功能。

  • 定义:NetworkBehaviour 中定义一个方法,并在其上方添加 [ServerRpc] 特性。方法名通常以 ServerRpc 结尾(约定俗成)。
    [ServerRpc]
    void RequestShootServerRpc(Vector3 direction)
    {// 此代码将在服务器上执行Debug.Log($"Server received shoot request from client {OwnerClientId} in direction {direction}");// ... 处理射击逻辑 ...
    }
    
  • 调用: 客户端上的 NetworkBehaviour 实例可以直接调用这个带 ServerRpc 特性的方法。Netcode 会自动将调用请求发送到服务器上对应的 NetworkObjectNetworkBehaviour 实例去执行。
  • 要求: 默认情况下,只有该 NetworkObject 的所有者 (Owner Client) 才能调用其上的 ServerRpc。可以通过 RequireOwnership = false 参数放宽限制,但这通常需要额外的安全检查。

3.3.3 ClientRpc

用于实现服务器调用一个或多个客户端方法的功能。

  • 定义:NetworkBehaviour 中定义一个方法,并在其上方添加 [ClientRpc] 特性。方法名通常以 ClientRpc 结尾。
    [ClientRpc]
    void PlayImpactEffectClientRpc(Vector3 position)
    {// 此代码将在所有客户端上执行(或特定客户端,取决于发送参数)Debug.Log($"Client received request to play impact effect at {position}");// ... 在指定位置播放特效 ...
    }
    
  • 调用: 只有服务器上的 NetworkBehaviour 实例可以调用 ClientRpc 方法。Netcode 会将调用请求发送给一个或多个客户端上对应的 NetworkObjectNetworkBehaviour 实例去执行。
  • 目标客户端: 可以通过 ClientRpcParams 指定 RPC 发送给哪些客户端(默认是所有客户端)。

四、实践:搭建基础网络同步场景

现在,让我们动手用 Netcode 实现一个最简单的目标:让一个玩家立方体能在网络上移动,并且其他玩家能看到它的位置同步。

4.1 准备工作

4.1.1 安装 Netcode 包

  1. 打开 Unity Hub,创建一个新的 3D 项目(或使用现有项目)。
  2. 在 Unity 编辑器中,打开 Window -> Package Manager
  3. 在 Package Manager 窗口左上角,选择 Unity Registry
  4. 在搜索框中输入 Netcode for GameObjects
  5. 找到 Netcode for GameObjects 包,点击 Install

4.1.2 创建基础场景

  1. 创建一个新的空场景 (File -> New Scene)。
  2. 在场景中创建一个 3D Plane 作为地面 (GameObject -> 3D Object -> Plane)。调整其大小和位置。
  3. 创建一个 3D Cube 作为玩家代表 (GameObject -> 3D Object -> Cube)。将其命名为 PlayerPrefab
  4. PlayerPrefab 从 Hierarchy 拖拽到 Project 窗口,将其创建为预制体 (Prefab)。完成后可以删除场景中的 PlayerPrefab 实例。

4.2 配置 NetworkManager

  1. 在 Hierarchy 窗口创建一个空 GameObject,命名为 NetworkManager
  2. 选中 NetworkManager 对象,在 Inspector 窗口点击 Add Component,搜索并添加 NetworkManager 组件。
  3. 再次点击 Add Component,搜索并添加 Unity Transport 组件(或其他你选择的 Transport)。NetworkManager 会自动检测到它。如果未自动关联,需要手动将 Unity Transport 组件拖拽到 NetworkManagerNetwork Transport 字段上。
  4. NetworkManager 组件中,找到 Player Prefab 字段,将我们之前创建的 PlayerPrefab 从 Project 窗口拖拽到这个字段上。

4.3 创建玩家同步脚本

现在我们需要编写脚本来控制玩家移动,并确保这个移动能被网络同步。

4.3.1 创建 PlayerController 脚本

  1. 在 Project 窗口创建一个新的 C# 脚本,命名为 PlayerController
  2. 打开脚本,修改代码如下:
using Unity.Netcode;
using UnityEngine;// 继承自 NetworkBehaviour 而不是 MonoBehaviour
public class PlayerController : NetworkBehaviour
{public float moveSpeed = 5.0f;// Update is called once per framevoid Update(){// 核心:只允许对象的所有者 (Owner) 控制它// 如果当前脚本实例不是网络对象的所有者,则不执行移动逻辑if (!IsOwner) return;// 简单的键盘输入移动逻辑float horizontal = Input.GetAxis("Horizontal");float vertical = Input.GetAxis("Vertical");Vector3 moveDirection = new Vector3(horizontal, 0, vertical);transform.Translate(moveDirection * moveSpeed * Time.deltaTime);}
}

关键点解释:

  • using Unity.Netcode;: 引入 Netcode 命名空间。
  • public class PlayerController : NetworkBehaviour: 脚本必须继承自 NetworkBehaviour
  • if (!IsOwner) return;: 这是网络编程中极其重要的一行。IsOwnerNetworkBehaviour 提供的一个布尔属性,表示当前执行这段代码的实例是否是这个网络对象的所有者(即控制这个玩家的那个客户端)。我们只允许玩家控制自己的角色,其他客户端上的这个角色的实例(代理)不应该响应本地输入。

4.3.2 添加 NetworkObject 组件

  1. 选中 Project 窗口中的 PlayerPrefab
  2. 在 Inspector 窗口点击 Add Component,搜索并添加 NetworkObject 组件。这是必须的,否则 Netcode 无法识别和管理这个对象。

4.3.3 实现位置同步 (使用 NetworkTransform)

虽然我们可以使用 NetworkVariable<Vector3> 手动同步位置,但对于 Transform 的同步,Netcode 提供了一个更方便的内置组件:NetworkTransform

4.3.4 实现基本移动逻辑

上面的 PlayerController 脚本已经包含了基本的移动逻辑,并且通过 IsOwner 检查确保只有本地玩家可以控制。

4.4 添加 NetworkTransform 组件

  1. 继续选中 PlayerPrefab
  2. 在 Inspector 窗口点击 Add Component,搜索并添加 NetworkTransform 组件。
  3. NetworkTransform 组件会自动处理 Transform(位置、旋转、缩放)的同步。默认情况下,它会同步位置和旋转。你可以根据需要在 Inspector 中调整其同步选项。

确认 PlayerPrefab 配置:
现在,你的 PlayerPrefab 应该至少包含以下组件:

  • Transform (自带)
  • Mesh Filter & Renderer (Cube 自带)
  • Box Collider (Cube 自带)
  • NetworkObject (必须添加)
  • PlayerController (我们创建的脚本)
  • NetworkTransform (用于同步位置)

4.5 测试场景

现在是见证奇迹的时刻!我们需要启动一个服务器(或主机)和一个客户端来测试同步。

4.5.1 构建与运行

  1. 保存场景 (File -> Save Scene)。
  2. 打开 File -> Build Settings
  3. 确保你的当前场景已经添加到 Scenes In Build 列表中 (如果列表为空,点击 Add Open Scenes)。
  4. 选择目标平台为 PC, Mac & Linux Standalone
  5. 点击 Build,选择一个文件夹来存放构建好的可执行文件。
  6. 不要关闭 Unity 编辑器
  7. 构建完成后,运行刚才生成的可执行文件 (.exe)。在这个运行的程序窗口中,找到屏幕上(或者你需要添加简单的 UI 按钮)启动 HostServer 的方式。如果你的 NetworkManager GameObject 在场景中可见,它默认会显示 Start Host, Start Server, Start Client 的按钮。点击 Start Host(这将使这个实例既是服务器又是客户端)。
  8. 回到 Unity 编辑器,按下 Play 按钮运行游戏。在编辑器的 Game 窗口中,找到 NetworkManager 的按钮(如果 Inspector 可见)或通过 UI,点击 Start Client
  9. 现在你应该有两个游戏窗口在运行:一个是独立构建的 Host/Server,另一个是 Unity 编辑器中的 Client。

4.5.2 观察同步效果

  • 你应该能在每个窗口中看到两个立方体(一个代表 Host 玩家,一个代表 Client 玩家)。
  • 尝试在一个窗口中使用方向键(WASD 或箭头键,取决于你的 Input Manager 设置)移动玩家立方体。
  • 观察另一个窗口中对应的立方体,你会发现它的位置也实时更新了!这就是 NetworkTransform 实现的位置同步效果。
  • 尝试在另一个窗口中移动它的玩家立方体,同样,第一个窗口中的对应立方体也会同步移动。

恭喜!你已经成功搭建了一个最基础的网络同步场景!

五、常见问题与进阶思考

这个简单的示例只是网络编程的冰山一角。在实际开发中,你会遇到更多挑战:

5.1 延迟 (Latency) 问题

我们刚才的测试很可能是在本地机器上进行的,网络延迟几乎为零。但在真实网络环境中,延迟是不可避免的。这会导致:

  • 输入延迟: 你按下按键到服务器响应再反馈回来需要时间。
  • 状态更新延迟: 你看到其他玩家的位置总是“过去”的位置。

解决方法:

  • 客户端预测 (Client-Side Prediction): 客户端不等待服务器确认,立即根据输入移动自己的角色,然后根据服务器的权威状态进行修正。这让本地玩家感觉响应迅速。
  • 插值 (Interpolation): 平滑地移动远程玩家的代理,使其从上一个已知位置移动到最新的已知位置,而不是瞬间跳变。
  • 外插 (Extrapolation): 在等待下一个状态更新时,基于当前速度和方向预测远程玩家的未来位置(风险是预测可能出错)。

NetworkTransform 组件内部已经实现了一些基础的插值。

5.2 NAT 穿透

在 P2P 模式或需要客户端直连的场景下,NAT(网络地址转换,家庭路由器常用)会阻止外部直接连接到你的电脑。这需要 NAT 穿透技术(如 STUN/TURN 服务器)或使用 Relay 服务器(所有数据通过中间服务器转发,类似 C/S,但服务器不处理逻辑)。Unity Transport 配合 Unity Relay 服务可以帮助解决这个问题。

5.3 安全性考量

在 C/S 架构中,永远不要信任客户端。所有重要的逻辑(如伤害计算、移动合法性验证、技能冷却)都应该在服务器上进行权威判断。客户端发送的 RPC 请求应被视为“请求”而非“命令”,服务器需要验证其有效性。

5.4 下一步学习

  • RPC 实践: 尝试使用 ServerRpcClientRpc 实现简单的动作同步,比如按下空格键让所有玩家的角色都跳一下(在服务器上处理跳跃逻辑)。
  • NetworkVariable 实践: 使用 NetworkVariable 同步玩家的生命值或得分,并在 UI 上显示。
  • 更复杂的同步: 了解如何同步动画状态 (NetworkAnimator)、自定义数据结构。
  • 官方示例: 学习 Unity 提供的 Netcode 示例项目 (如 Boss Room)。
  • 网络优化: 了解如何减少网络流量,处理丢包和网络抖动。

六、总结

今天我们深入了解了网络游戏开发的基础,并迈出了使用 Unity Netcode for GameObjects 的第一步。核心要点回顾:

  1. 网络架构: 理解了客户端/服务器 (C/S) 和点对点 (P2P) 架构的原理、优缺点及适用场景。C/S 是目前主流且 Netcode 主要支持的模式。
  2. 核心同步概念: 掌握了状态同步(持续同步数据,如位置)和远程过程调用 (RPC)(触发事件或命令,如开火)的基本原理和用途。
  3. Unity Netcode 基础: 认识了 Netcode for GameObjects 的核心组件 (NetworkManager, NetworkObject, NetworkBehaviour) 以及实现同步的关键机制 (NetworkVariable<T>, ServerRpc, ClientRpc)。
  4. 入门实践: 通过 NetworkTransform 组件,成功搭建了一个简单的网络场景,实现了玩家位置的基本同步,并理解了 IsOwner 检查的重要性。
  5. 进阶考量: 初步了解了网络延迟、NAT 穿透、安全性等实际开发中需要关注的问题,并明确了后续学习的方向。

网络编程是一个广阔且充满挑战的领域,但掌握了基础概念和工具,你就能为你的游戏打开多人互动的大门。继续探索,不断实践,你将能够创造出更加丰富和有趣的在线游戏体验!下一天,我们将开始整合所学知识,启动一个小型综合项目。敬请期待!


相关文章:

  • Word/WPS 删除最后一页空白页,且保持前面布局样式不变
  • Cribl 上传lookup 表,传入数据进event
  • 【Java面试笔记:进阶】21.Java并发类库提供的线程池有哪几种? 分别有什么特点?
  • 【软考-架构】13.5、中间件
  • 某海关某署 【瑞数6】逆向分析
  • 《代码之美:静态分析工具与 CI 集成详解》
  • 豆包,Kim,deepseek对比
  • LLM(大语言模型)技术的最新进展可总结
  • 多模态大语言模型arxiv论文略读(四十三)
  • 未来医院已来:AI如何实现无死角安全监控
  • PowerBI动态路径获取数据技巧
  • 腾讯CSIG一面
  • 35-疫苗预约管理系统(微服务)
  • qt事件过滤与传递机制
  • 华为云Astro canvas大屏与iotDA是怎样通过数据接入、数据中心的功能传输和通讯的?
  • 经典反转结构——案例分析
  • Java 实现目录递归拷贝
  • django之账号管理功能
  • 用Python做有趣的AI项目1:用 TensorFlow 实现图像分类(识别猫、狗、汽车等)
  • lvgl 实现横向滑动,并且捕获最中间那个元素
  • 国家统计局:一季度规模以上工业企业利润延续持续恢复态势
  • 中公教育:去年全面扭亏,经营性现金流增长169.6%
  • 四川一国企“80后”掌门人为报领导“知遇之恩”,盲目决策致数亿损失
  • 30天内三访中国,宝马董事长:没有一家公司可以在全球价值链外独立运行
  • 公安部知识产权犯罪侦查局:侦破盗录传播春节档院线电影刑案25起
  • 李良生已任应急管理部党委委员、政治部主任