做局域网联机这个需求,最初我以为就是两个客户端互发坐标而已,一台电脑做服务器,其余客户端连上来,回合制发点数据就行。真正动手才发现,Unity里局域网联机的坑比想象中多得多——旧教程还在推UNET,新项目已经全部换Netcode for GameObjects,两者API完全不兼容;好不容易连上了,防火墙又把UDP端口拦了;连上了,角色却穿模或者瞬移;再往下深挖,TickRate、网络变量权限、动态生成的Spawn权限,每个地方都能卡你半天。
这篇内容基于Unity 2021.3 LTS加Netcode for GameObjects 1.x,从方案选型讲到环境配置,从移动同步Demo写到房间自动发现,再把联机调试里我实际踩过的六个问题完整拆一遍,最后给出一套适用于局域网场景的带宽和延迟优化思路。适合第一次做局域网联机的Unity开发者,也适合正在评估“用官方方案还是第三方插件”的团队参考。
1. 从需求出发:你的局域网联机到底属于哪一派
1.1 同步粒度决定技术选型
局域网联机的第一件事不是打开编辑器写脚本,而是先回答一个问题:你要同步什么。
市面上所有联机方案本质上分成两条路线。第一种是状态同步,服务器是唯一权威源,所有角色的位置、血量、得分、拾取记录都由服务器计算并下发,客户端只负责表现。第二种是帧同步,服务器不计算游戏逻辑,它只收集每个客户端的操作指令,然后以固定的节奏把所有人的指令转发给所有客户端,每个客户端自己跑同一套逻辑,跑出相同的结果。
两者的适用场景差异很大。RPG、射击、生存建造这类不确定性强的玩法,状态同步更合适,因为每一帧都有大量随机事件,服务器做权威校验能避免玩家各跑各的结论。格斗游戏、RTS、部分休闲竞技,因为需要极其严格的输入公平性和历史回放能力,帧同步才是更主流的选择。
局域网和公网在这一点上没有本质区别,只是延迟从几十甚至几百毫秒降到了几毫秒。但这会带来一个新的倾向:很多人误以为局域网延迟低,就不需要设计同步策略了,实际上同步策略选错,局域网也会翻车。比如在状态同步方案里,如果代码写得像帧同步一样依赖每个客户端的本地运算,一旦某个设备的帧率波动,两台机器的物理引擎产生微小差异,几分钟后角色位置就会明显分叉。
1.2 权威服务器不是公网专用概念
很多初学者有一种错觉:局域网联机就是点对点,没有服务器。严格来说,多数局域网联机游戏确实不跑独立服,但“没有独立服”不等于“没有权威端”。
Netcode for Games的标准做法是Host模式,也就是Host端同时扮演服务器和客户端。Host拥有所有NetworkVariable的写权限,决定角色是否真的可以移动、攻击是否命中、物品是否被捡起来。其他客户端把操作意图通过ServerRpc发给Host,由Host逻辑校验后,再通过ClientRpc或NetworkVariable把结果同步出去。
这个设计看着多绕了一圈,但它解决了一个核心问题:一致性。如果所有客户端各自修改一个共享数据,A客户端改了血量,B客户端没改,后面所有逻辑都会乱套。局域网虽然只有几毫秒延迟,多绕一圈的代价微乎其微,但换来的数据一致性是巨大的。
所以我在做局域网Demo时也坚持这个架构:本地玩家操作自己的角色,移动的最终确认交给Host,Host在每帧计算完权威位置后再通过NetworkTransform同步给所有客户端。这套架构在局域网环境下完全感受不到额外时延,却能在后续扩展时避免大量并发问题。
1.3 现成网络方案横评:为什么我选了Netcode for GameObject
目前Unity环境下的局域网联机,主流选项基本是四个:UNET(已废弃)、Netcode for GameObjects(官方)、Mirror(社区方案)、Photon PUN 2(商业方案)。
先排除UNET。搜局域网联机教程,目前仍然能搜到大量UNET时代的代码,涉及NetworkManager、NetworkServer、NetworkClient这些类。在Unity 2021之后,这些类已经不在官方包里,强行找历史包接入,要么API不兼容,要么在IL2CPP打包时出现各种奇怪的报错。一句话:现在新项目再碰UNET,纯粹是给自己挖坑。
Mirror是当年HLAPI被砍之后由社区接棒维护的方案,社区活跃度高,文档和视频教程也很丰富,积累了非常多生产环境的踩坑总结。如果你的团队里有人特别熟悉Mirror的API,选它完全没有问题。
PUN 2则是一个商业化的可选项,跨平台消息服务做得成熟,但它的核心能力在云端,纯局域网场景需要额外依赖AppId和云端的房间配置服务,反而不纯粹。
我最终选择Netcode for GameObjects,理由很直接:官方维护、和Unity Transport传输层配合最紧密、API设计比较现代,NetworkVariable与RPC的概念分层清晰,对局域网场景来说足够用。它的短板也很明确——比较新,一些边界场景的文档还不够完善,遇到问题需要在Unity官方论坛和GitHub Issue里翻答案。
这段取舍在章节后面会反复出现,因为后面的每一个坑,几乎都和框架的边界行为有关。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建:Netcode for GameObjects的安装与NetworkManager配置细节
2.1 版本组合别乱配,Transport和Netcode必须同步
凡是做Unity联机的人,几乎都在Package Manager里撞过版本坑。Netcode本身只是一套API,真正的网络收发是由Unity Transport包执行的,这两个包的版本必须匹配。Netcode 1.x对应Transport 2.x,如果项目中同时混入了Transport 1.x和2.x,或者Netcode版本与Transport大版本不匹配,运行时会直接报DllNotFoundException或各种稀奇古怪的加载错误。
我建议把项目固定在Unity 2021.3 LTS或更高版本,如果你在用2022 LTS也可以。安装方式没什么特殊的:Window -> Package Manager,左上角切换到Unity Registry,搜索Netcode for GameObjects,直接安装。Unity会自动把配套的Unity Transport一起拉进来,正常情况下不需要手动单独安装Transport。
这里有一个很小的细节:安装后检查一下Project Settings里是否生成了Netcode for GameObjects的配置分页,如果没有,说明包没有正常加载,需要重启编辑器。我曾经在没有重启编辑器的情况下直接添加NetworkManager组件,结果Inspector面板一片空白,排查了半小时才知道是包没有完成重编译。
2.2 NetworkManager的初始化与连接参数
场景里新建一个空物体,命名为NetworkManager,挂上NetworkManager组件和Unity Transport组件,这是最标准的接法。
Unity Transport上有一个Server Listen Port,默认是9998。这个端口就是局域网内所有客户端要连接的目标端口,整个网络房间里所有人都要连同一个IP加这个端口。局域网场景里不需要配置URL或域名,没有DNS解析这回事,客户端只要知道IPv4地址和端口就能建立连接。
在Net
