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 交互流程如下:
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
而不是 MonoBehaviour
。NetworkBehaviour
提供了访问网络状态(如 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 会自动将调用请求发送到服务器上对应的NetworkObject
的NetworkBehaviour
实例去执行。 - 要求: 默认情况下,只有该
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 会将调用请求发送给一个或多个客户端上对应的NetworkObject
的NetworkBehaviour
实例去执行。 - 目标客户端: 可以通过
ClientRpcParams
指定 RPC 发送给哪些客户端(默认是所有客户端)。
四、实践:搭建基础网络同步场景
现在,让我们动手用 Netcode 实现一个最简单的目标:让一个玩家立方体能在网络上移动,并且其他玩家能看到它的位置同步。
4.1 准备工作
4.1.1 安装 Netcode 包
- 打开 Unity Hub,创建一个新的 3D 项目(或使用现有项目)。
- 在 Unity 编辑器中,打开
Window
->Package Manager
。 - 在 Package Manager 窗口左上角,选择
Unity Registry
。 - 在搜索框中输入
Netcode for GameObjects
。 - 找到
Netcode for GameObjects
包,点击Install
。
4.1.2 创建基础场景
- 创建一个新的空场景 (
File
->New Scene
)。 - 在场景中创建一个 3D Plane 作为地面 (
GameObject
->3D Object
->Plane
)。调整其大小和位置。 - 创建一个 3D Cube 作为玩家代表 (
GameObject
->3D Object
->Cube
)。将其命名为PlayerPrefab
。 - 将
PlayerPrefab
从 Hierarchy 拖拽到 Project 窗口,将其创建为预制体 (Prefab)。完成后可以删除场景中的PlayerPrefab
实例。
4.2 配置 NetworkManager
- 在 Hierarchy 窗口创建一个空 GameObject,命名为
NetworkManager
。 - 选中
NetworkManager
对象,在 Inspector 窗口点击Add Component
,搜索并添加NetworkManager
组件。 - 再次点击
Add Component
,搜索并添加Unity Transport
组件(或其他你选择的 Transport)。NetworkManager
会自动检测到它。如果未自动关联,需要手动将Unity Transport
组件拖拽到NetworkManager
的Network Transport
字段上。 - 在
NetworkManager
组件中,找到Player Prefab
字段,将我们之前创建的PlayerPrefab
从 Project 窗口拖拽到这个字段上。
4.3 创建玩家同步脚本
现在我们需要编写脚本来控制玩家移动,并确保这个移动能被网络同步。
4.3.1 创建 PlayerController 脚本
- 在 Project 窗口创建一个新的 C# 脚本,命名为
PlayerController
。 - 打开脚本,修改代码如下:
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;
: 这是网络编程中极其重要的一行。IsOwner
是NetworkBehaviour
提供的一个布尔属性,表示当前执行这段代码的实例是否是这个网络对象的所有者(即控制这个玩家的那个客户端)。我们只允许玩家控制自己的角色,其他客户端上的这个角色的实例(代理)不应该响应本地输入。
4.3.2 添加 NetworkObject 组件
- 选中 Project 窗口中的
PlayerPrefab
。 - 在 Inspector 窗口点击
Add Component
,搜索并添加NetworkObject
组件。这是必须的,否则 Netcode 无法识别和管理这个对象。
4.3.3 实现位置同步 (使用 NetworkTransform)
虽然我们可以使用 NetworkVariable<Vector3>
手动同步位置,但对于 Transform 的同步,Netcode 提供了一个更方便的内置组件:NetworkTransform
。
4.3.4 实现基本移动逻辑
上面的 PlayerController
脚本已经包含了基本的移动逻辑,并且通过 IsOwner
检查确保只有本地玩家可以控制。
4.4 添加 NetworkTransform 组件
- 继续选中
PlayerPrefab
。 - 在 Inspector 窗口点击
Add Component
,搜索并添加NetworkTransform
组件。 NetworkTransform
组件会自动处理Transform
(位置、旋转、缩放)的同步。默认情况下,它会同步位置和旋转。你可以根据需要在 Inspector 中调整其同步选项。
确认 PlayerPrefab 配置:
现在,你的 PlayerPrefab
应该至少包含以下组件:
- Transform (自带)
- Mesh Filter & Renderer (Cube 自带)
- Box Collider (Cube 自带)
- NetworkObject (必须添加)
- PlayerController (我们创建的脚本)
- NetworkTransform (用于同步位置)
4.5 测试场景
现在是见证奇迹的时刻!我们需要启动一个服务器(或主机)和一个客户端来测试同步。
4.5.1 构建与运行
- 保存场景 (
File
->Save Scene
)。 - 打开
File
->Build Settings
。 - 确保你的当前场景已经添加到
Scenes In Build
列表中 (如果列表为空,点击Add Open Scenes
)。 - 选择目标平台为
PC, Mac & Linux Standalone
。 - 点击
Build
,选择一个文件夹来存放构建好的可执行文件。 - 不要关闭 Unity 编辑器。
- 构建完成后,运行刚才生成的可执行文件 (.exe)。在这个运行的程序窗口中,找到屏幕上(或者你需要添加简单的 UI 按钮)启动
Host
或Server
的方式。如果你的NetworkManager
GameObject 在场景中可见,它默认会显示Start Host
,Start Server
,Start Client
的按钮。点击Start Host
(这将使这个实例既是服务器又是客户端)。 - 回到 Unity 编辑器,按下 Play 按钮运行游戏。在编辑器的 Game 窗口中,找到
NetworkManager
的按钮(如果 Inspector 可见)或通过 UI,点击Start Client
。 - 现在你应该有两个游戏窗口在运行:一个是独立构建的 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 实践: 尝试使用
ServerRpc
和ClientRpc
实现简单的动作同步,比如按下空格键让所有玩家的角色都跳一下(在服务器上处理跳跃逻辑)。 - NetworkVariable 实践: 使用
NetworkVariable
同步玩家的生命值或得分,并在 UI 上显示。 - 更复杂的同步: 了解如何同步动画状态 (
NetworkAnimator
)、自定义数据结构。 - 官方示例: 学习 Unity 提供的 Netcode 示例项目 (如
Boss Room
)。 - 网络优化: 了解如何减少网络流量,处理丢包和网络抖动。
六、总结
今天我们深入了解了网络游戏开发的基础,并迈出了使用 Unity Netcode for GameObjects 的第一步。核心要点回顾:
- 网络架构: 理解了客户端/服务器 (C/S) 和点对点 (P2P) 架构的原理、优缺点及适用场景。C/S 是目前主流且 Netcode 主要支持的模式。
- 核心同步概念: 掌握了状态同步(持续同步数据,如位置)和远程过程调用 (RPC)(触发事件或命令,如开火)的基本原理和用途。
- Unity Netcode 基础: 认识了 Netcode for GameObjects 的核心组件 (
NetworkManager
,NetworkObject
,NetworkBehaviour
) 以及实现同步的关键机制 (NetworkVariable<T>
,ServerRpc
,ClientRpc
)。 - 入门实践: 通过
NetworkTransform
组件,成功搭建了一个简单的网络场景,实现了玩家位置的基本同步,并理解了IsOwner
检查的重要性。 - 进阶考量: 初步了解了网络延迟、NAT 穿透、安全性等实际开发中需要关注的问题,并明确了后续学习的方向。
网络编程是一个广阔且充满挑战的领域,但掌握了基础概念和工具,你就能为你的游戏打开多人互动的大门。继续探索,不断实践,你将能够创造出更加丰富和有趣的在线游戏体验!下一天,我们将开始整合所学知识,启动一个小型综合项目。敬请期待!
相关文章:
Unity网络编程入门:掌握Netcode for GameObjects实现多人游戏基础(Day 39)
Langchain系列文章目录 01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...
LeetCode100题
LeetCode100 两数之和 遍历数组,以哈希表存数与下标,边存边查,速找和为目标值的两数下标 class Solution {public int[] twoSum(int[] nums, int target) {int[] ansnew int[2];HashMap<Integer,Integer> mapnew HashMap<>();…...
鸿蒙代码@Builder
#代码如下: Entry Component struct CardExample {State title: string "欢迎使用鸿蒙";State content: string "这是一段自定义内容";build() {Column() {this.MyCard({ title: this.title, content: this.content })}.padding(20)}BuilderM…...
Gewechat启动启动报错
Centos7,测试连接时发现这个错误。 [rootxin ~]# curl -i -X POST http://127.0.0.1:2531/v2/api/tools/getTokenId curl: (56) Recv failure: Connection reset by peer 1、删除原容器,重新构建。 docker run -itd \--name gewe \--privileged \-v /ro…...
硅谷甄选41集-71集
第四十三集:完全按照视频敲代码的话会发现左侧顶部tabbar的display:flex失效了,是因为拆分开的子组件里面多了一个div,去掉就好了,vue3不需要再额外包裹元素。因为路径变化了,所以找不到图片的话在前面再加一个…。 第四十五集&am…...
PyQt6实例_消息工具_使用与完整代码分享
目录 使用 每日消息 全局查询 更新数据库 代码 数据库表创建 代码-数据库相关操作 代码-界面与操作逻辑 视频 使用 工具有三个面板:每日消息、全局查询、更新数据库 “每日消息”和“全局查询”,数据源:同花顺7x24小时快讯 “更新…...
docker配置mysql遇到的问题:网络连接超时、启动mysql失败、navicat无法远程连接mysql
目录 1.网络超时 方式1. 网络连接问题 方式2. Docker镜像源问题 方式3.使用国内镜像源 2.启动mysql镜像失败 3.navicat无法远程连接mysql 1.网络超时 安装MySQL时出现超时问题,可能由多种原因导致: 方式1. 网络连接问题 原因:网络不稳定…...
【虚幻C++笔记】碰撞检测
目录 碰撞检测参数详情示例用法 碰撞检测 显示名称中文名称CSphere Trace By Channel按通道进行球体追踪UKismetSystemLibrary::SphereTraceSingleSphere Trace By Profile按描述文件进行球体追踪UKismetSystemLibrary::SphereTraceSingleByProfileSphere Trace For Objects针…...
SpringBoot集成WebSocket,单元测试执行报错
问题描述 SpringBoot集成了WebSocket,单元测试启动后会报如下错误:javax.websocket.server.ServerContainer not available 这是因为SpringBootTest启动时不会启动服务器,所以WebSocket会报错。 解决方案 在注解中添加 webEnvironmen…...
Git基本操作
1. 安装与配置 安装:你可以从 Git 官方网站 下载 Windows 版本的安装程序。运行安装程序,在安装过程中,你可以按照默认设置进行安装,也可以根据自己的需求进行调整。配置:安装完成后,打开 Git Bash&#x…...
C++异步并发支持库future
future: 1.利用共享状态来异步的获取提供者的值 2.future处于共享状态就绪时才是有效的 3.future不能拷贝构造,只能移动构造,并且移动构造后共享状态失效 std::future::get 1.当共享状态就绪时,返回存储在共享状态中的值。 2…...
c++学习小结
内存分配 空间 栈区(stack)。编译器⾃动分配与释放,主要存放函数的参数值,局部变量值等,连续的内存空 间,由⾼地址向低地址扩展。 堆区(heap) 。由程序员分配与释放;不…...
Pygame物理模拟:实现重力、弹跳与简单物理引擎
Pygame物理模拟:实现重力、弹跳与简单物理引擎 大家好,欢迎来到本期的技术分享!今天我们将一起探讨如何使用Python和Pygame库来实现一个简单的物理模拟系统,其中包括重力、弹跳以及一个基础的物理引擎。如果你对游戏开发或者物理仿真感兴趣,那么这篇文章一定会让你受益匪…...
Python dotenv 使用指南:轻松管理项目环境变量
一、为什么要使用环境变量管理? 很多开发者容易把自己开发的项目上传到Github上,但偶尔会忘记把数据库密码、支付接口密钥等敏感信息和谐掉,当代码提交上去时,这些信息就像裸奔一样暴露在所有人面前。更糟糕的是,不同…...
网络攻防第一~四集
来源于一下 【小迪安全】红蓝对抗 | 网络攻防 | V2023全栈培训_哔哩哔哩_bilibili 目录 第一集 第二集 第一集 web架构包括系统、中间件、程序源码、数据库 系统 windows、linux、windows server 中间件 是前端语言和数据库是当做一个桥梁,当做解析作用&…...
TI---sysconfig生成宏
核心内容概览 1. 宏定义的总体作用 SysConfig生成的宏定义是硬件配置的符号化映射,将图形化界面的配置参数转化为可直接引用的编译时常量,核心价值包括: 免硬编码:避免手动写入硬件参数(如引脚号、波特率࿰…...
【C】初阶数据结构13 -- 快速排序
本篇文章主要讲解经典的排序算法 -- 快速排序算法 目录 1 递归版本的快速排序 1) 算法思想 (1) hoare 版本 (2) 双指针版本 (3) 挖坑法 2) 代码 3) 时间复杂度…...
Spring Boot 3.4 实战指南:从性能优化到云原生增强
一、核心新特性概览 Spring Boot 3.4 于 2024 年 11 月正式发布,带来 6 大维度的 28 项改进。以下是实战开发中最具价值的特性: 1. 性能革命:虚拟线程与 HTTP 客户端优化 虚拟线程支持:Java 21 引入的虚拟线程在 Spring Boot 3…...
Git分支重命名与推送参数解析
这两个参数的解释如下: git branch -M master 中的 -M 参数 -M 是 --move --force 的组合简写,表示强制重命名当前分支为 master。如果当前分支已经存在名为 master 的分支,-M 会强制覆盖它(慎用,可能导致数据丢失&…...
深度学习中的预训练与微调:从基础概念到实战应用全解析
摘要 本文系统解析深度学习中预训练与微调技术,涵盖核心概念、技术优势、模型复用策略、与迁移学习的结合方式,以及微调过程中网络参数更新机制、模型状态分类等内容。同时深入分析深层神经网络训练难点如梯度消失/爆炸问题,为模型优化提供理…...
EMC-148.5MHz或85.5辐射超标-HDMI
EMC 148.5MHz或85.5辐射超标-HDMI 遇到了一台设备过不了EMC ,经排查主要是显示器的HDMI问题 解决办法看看能否更换好一点的HDMI线缆...
DeepSeek系列(9):团队协作最佳实践
团队知识库构建 在知识经济时代,团队知识的有效管理和传递是组织核心竞争力的关键。DeepSeek可以成为打造高效团队知识库的得力助手,让知识管理从繁重工作变为自动化流程。 知识库架构设计 多层次知识结构 一个高效的团队知识库应具备清晰的层级结构,DeepSeek可以协助:…...
信息系统项目管理工程师备考计算类真题讲解十
一、立项管理 1)折现率和折现系数:折现也叫贴现,就是把将来某个时间点的金额换算成现在时间点的等值金额。折现时所使用的利率叫折现率,也叫贴现率。 若n年后能收F元,那么这些钱在现在的价值,就是现值&am…...
第1章 基础知识
1.1 机器语言 1.2 汇编语言的产生 用汇编语言编写程序的工作过程如下: 1.编写程序:汇编程序包括汇编指令、伪指令、其他符号,如下图。其中,“伪指令”并不是由计算机直接执行的指令,而是帮助编译器完成“编译”的符号。 2.编译:将汇编程序转换成机器码。 3.计算机执行。 …...
16.【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--微服务基础工具与技术--Github Action
GitHub Actions 是 GitHub 提供的持续集成和持续部署(CI/CD)平台,它允许我们自动化软件开发工作流程。通过 GitHub Actions,我们可以构建、测试和部署代码,而无需手动干预。 一、基本概念 1.1 Workflow(工作流) 工作…...
MySQL 事务隔离级别详解
以下是 MySQL 支持的四种事务隔离级别及其特性,按并发安全性从低到高排列: 1. 读未提交 (Read Uncommitted) 问题: 脏读 (Dirty Read):事务可读取其他事务未提交的数据。不可重复读 (Non-repeatable Read)&am…...
A. Ambitious Kid
time limit per test 1 second memory limit per test 256 megabytes Chaneka, Pak Chaneks child, is an ambitious kid, so Pak Chanek gives her the following problem to test her ambition. Given an array of integers [A1,A2,A3,…,AN][A1,A2,A3,…,AN]. In one o…...
C19-while循环及for循环等价引入
一 while的表达式 //while的表达式有三个 #include <stdio.h> int main() { int sum; int data1; //第一个表达式,条件的初始值while(data<100){ //第二个表达式,条件的临界值sumsumdata;data; //第三个表达式,条件变化}printf("0至100的和是:%d\n",sum);…...
华为盘古OS深度评测:构建AI自进化系统的实践密码
华为盘古OS通过分布式AI内核与自适应学习框架的深度耦合,重新定义操作系统级智能能力。实测显示其AI任务调度效率较传统系统提升17倍,本文从智能体编排、持续学习机制、端云协同架构三个维度,解析如何基于DevKit 3.0打造具备认知进化能力的下…...
SpringBoot UserAgentUtils获取用户浏览器 操作系统设备统计 信息统计 日志入库
介绍 UserAgentUtils 是于处理用户代理(User-Agent)字符串的工具类,一般用于解析和处理浏览器、操作系统以及设备等相关信息,这些信息通常包含在接口请求的 User-Agent 字符串中。 这个库可以用于解析用户代理头,以提…...
PCL绘制点云+法线
读取的点云ASCII码文件,每行6个数据,3维坐标3维法向 #include <iostream> #include <fstream> #include <vector> #include <string> #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pc…...
DataStreamAPI实践原理——计算模型
引入 Apache Flink 是一个框架和分布式处理引擎,用于在 无边界 和 有边界 数据流上进行有状态的计 算。Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算。Flink可以处理批数据也可以处理流数据,本质上,流处理…...
【那些年踩过的坑】Docker换源加速详细教程(截至2025年4月)
由于各种网络政策,在国内访问DockerHub速度会非常缓慢,大家一般都会采取更换镜像源的方式来进行加速。但是,2024.6之后,由于政策的加强,大部分常见的镜像源已经无法使用,可能在更换镜像源后出现如下报错信息…...
【MCP】详细了解MCP协议:和function call的区别何在?如何使用MCP?
本文介绍了MCP大模型上下文协议的的概念,并对比了MCP协议和function call的区别,同时用python sdk为例介绍了mcp的使用方式。 1. 什么是MCP? 官网:https://modelcontextprotocol.io/introduction 2025年,Anthropic提出…...
交换机之配置系统基本信息(Basic Information of the Configuration System for Switches)
交换机之配置系统基本信息 本文章中的信息都是基于一些特定实验环境写的。文章中使用的所有设备最初均采用缺省配置启动。如果不按初始配置,有可能会导致本文中的部分或全部步骤失败。如果您使用的是真实网络设备,请确保您已经了解所有使用过的命令影响。…...
贝叶斯算法学习
贝叶斯算法学习 贝叶斯算法基础与原理应用场景主要分类优缺点简单示例代码实现 贝叶斯算法是基于贝叶斯定理的一种统计学习方法,在机器学习、数据挖掘、自然语言处理等领域有广泛应用。以下是其原理、应用和示例的详细介绍: 贝叶斯算法基础与原理 贝…...
Java 日志:掌握本地与网络日志技术
日志记录是软件开发中不可或缺的一部分,它为开发者提供了洞察应用程序行为、诊断问题和监控性能的手段。在 Java 生态系统中,日志框架如 Java Util Logging (JUL)、Log4j 和 Simple Logging Facade for Java (SLF4J) 提供了丰富的功能。然而,…...
线程池单例模式
线程池的概念 线程池是一种线程使用模式。 一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。…...
物联网安全解决方案介绍:有效利用现有的下一代防火墙
管理物联网设备安全的挑战 如今,随着IoT(物联网)的普及,可以集中管理相机、打印机、传感器、电器、机床等各种设备,并分析和有效利用从这些设备收集的数据。这些设备已成为商业环境中不可或缺的一部分,但设备的多样化使其难以管理。与PC、服务器和网络设备不同,识别物联…...
Java社区门诊系统源码 SaaS医院门诊系统源码 可上线运营
Java社区门诊系统源码 SaaS医院门诊系统源码 医院门诊系统适用于:社区卫生服务站、门诊部、诊所、村卫生室等,有上百家医疗机构正常使用;包括医保结算。 系统功能 (一)后端管理系统功能 用户管理:提供用…...
如何在 Windows 10 中使用 WSL 和 Debian 安装 Postgresql 和 Postgis
安装 Postgresql 和 Postgis 的常规方法需要设置多个二进制文件,并且工作流程通常在图形用户界面 (GUI) 上进行。我们希望找到一种在 Windows 10 中安装 Postgresql 和 Postgis 的方法,同时保留 Linux 的 shell 体验。本教程展示了在 Windows 10 中的 De…...
[论文解析]Mip-Splatting: Alias-free 3D Gaussian Splatting
Mip-Splatting: Alias-free 3D Gaussian Splatting 论文地址:https://arxiv.org/abs/2403.17888 源码地址:https://github.com/autonomousvision/mip-splatting 项目地址:https://niujinshuchong.github.io/mip-splatting/ 论文解读 两个主…...
MongoDB 入门使用教程
MongoDB 入门使用教程 MongoDB 是一个开源的 NoSQL 数据库,使用文档(JSON-like)存储数据,与传统的关系型数据库不同,它不依赖表结构和行列的约束。MongoDB 提供了强大的查询能力,支持高效的数据存储和检索…...
PowerBI动态路径获取数据技巧
PowerBI动态路径获取数据技巧 场景一:同事接力赛——不同电脑共用模板 (想象一下:小王做完报表要传给小李,结果路径总对不上怎么办?) 这种情况就像接力赛交接棒,每台电脑的账户名不同࿰…...
【数据结构】优先级队列
目录 1. 优先级队列概念 2. 优先级队列的模拟实现 2.1 堆的概念 2.2 堆的存储方式 2.3 堆的创建 2.3.1 向下调整的时间复杂度 2.3.2 建堆时间复杂度 2.3.3 向上调整的时间复杂度 2.4 堆的插入与删除 3. 堆的应用 4. 常用接口介绍 4.1 PriorityQueue的特性 4.2 Pri…...
Myweb项目——面试题总结
一.项目描述 项⽬概述:本项⽬在云服务上开发了⼀个后端服务器与前端⻚⾯为⼀体的⾳乐专辑 鉴赏⽹站,旨在为⽤⼾提供丰富的⾳乐专辑信息展⽰和优 质的浏览体验。 主要内容及技术: 后端开发:利⽤ C 语⾔构建后端服务器,…...
用高德API提取广州地铁线路(shp、excel)
目录 结果示例html文件——直观看出输出的效果excel文件——包括地铁的具体信息完整代码网络上现有的地铁数据要么过于老旧且不便于更新,要么过于定制化限定于具体的城市无法灵活调整得到自己真正想要的那部份数据。而使用高德的API可以非常方便得到全国各地的地铁数据,而且可…...
leetcode110 平衡二叉树
一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。 递归:…...
二、信息时代社会结构的转变
到了信息时代,以及在核武器的前提下,上述的社会结构的逻辑,就有了一个根 本性的转变,就是暴力的成本和收益,都在下降。 暴力的成本在降低。比如说枪支,它的制造和分发都变得非常容易。现在我们都 知道有 3D 打印,它就好像工业时代的印刷机,印刷圣经或者书籍,使知识更加 普及和容…...
Vue2+ElementUI实现无限级菜单
使用Vue2和ElementUI实现无限级菜单,通常菜单数据以树形结构存储,每个菜单包含多个子菜单 ,子菜单又可以继续包含更深层次的子菜单项。所以,需要使用递归形式,完成子项菜单的渲染。 这里,结合Element UI界面的el-menu和el-submenu组件来构建菜单结构,有子菜单时使用el-s…...