2、环境搭建与初始项目:创建Unity项目、导入Mirror网络库、配置NetworkManager、理解网络组件层级
好,咱们正式开始动手了。
这一章,说白了就是搭地基。地基稳不稳,直接决定你后面盖楼会不会塌。我在带团队做联机项目时,见过太多人一上来就写网络逻辑,结果项目结构一团糟,最后不得不重构。嗯,咱们别走那条弯路。
2.1 创建Unity项目
先创建一个新项目。我个人习惯用 3D Core 模板,因为联机游戏不一定非得是3D,但3D模板的灵活性最高。你想想看,2D项目也能用3D模板,反过来就不行了。
项目名称我建议用 MultiplayerGame,位置选个英文路径。为什么?因为Mirror某些底层库对中文路径支持不好,我曾经因为这个折腾了一下午。
2.2 导入Mirror网络库
Mirror的导入方式有两种,我分别说说。
方式一:从Asset Store导入(推荐新手)
- 打开 Window → Asset Store
- 搜索 "Mirror Networking"
- 点击 Import 即可
方式二:从GitHub导入(推荐团队协作)
// 在 Packages/manifest.json 中添加:
"com.mirror-networking.mirror": "https://github.com/vis2k/Mirror.git?path=Assets/Mirror"
我个人更推荐第二种。为什么?因为用Git管理项目时,第一种方式会把Mirror的meta文件搞得很乱。我团队里有个新人用第一种方式导入,结果每次pull代码都要重新导入一次,烦得很。
System.Runtime.CompilerServices.Unsafe 包。如果导入后报错,去 Package Manager 安装这个包。我遇到过三次这种问题,都是因为Unity版本升级后自动移除了这个依赖。
2.3 配置NetworkManager
导入完成后,咱们来配置核心组件——NetworkManager。
2.3.1 创建NetworkManager对象
在Hierarchy中创建一个空GameObject,命名为 NetworkManager。然后给它挂上两个组件:
NetworkManager(核心管理器)NetworkManagerHUD(调试用UI)
NetworkManagerHUD 是开发阶段的利器。它会在游戏运行时生成一个简单的UI,让你能快速启动Host、Client或Server。但记住,正式发布时一定要移除它——我见过有人把HUD带到生产环境,结果玩家能直接点"Stop Server"把整个房间搞崩。
2.3.2 关键参数配置
| 参数 | 推荐值 | 说明 |
|---|---|---|
| Network Address | localhost | 本地测试用,发布时改为服务器IP |
| Transport | KCP Transport | Mirror默认的可靠UDP传输 |
| Player Prefab | (稍后创建) | 玩家对象的预制体 |
| Auto Create Player | True | 客户端连接后自动生成玩家对象 |
这里有个细节:Transport 的选择。Mirror支持多种传输方式:
- KCP:基于UDP,速度快,适合动作游戏
- TCP:稳定但延迟高,适合回合制
- WebGL:浏览器专用
我一般默认用KCP。除非项目明确需要WebGL支持,否则别碰TCP——延迟高得让人抓狂。
2.4 理解网络组件层级
这是本章最核心的部分。很多新手搞不清NetworkManager、NetworkIdentity、NetworkBehaviour之间的关系。我画个图帮你理解:
NetworkManager(全局管理者)
└── 管理所有网络连接
└── 生成/销毁网络对象
NetworkIdentity(网络身份证)
└── 挂在每个网络对象上
└── 分配唯一的NetId
└── 控制对象的网络可见性
NetworkBehaviour(网络行为)
└── 继承自MonoBehaviour
└── 提供 [Command]、[ClientRpc] 等网络方法
└── 控制同步变量
说白了,这三者的关系就像公司架构:
- NetworkManager 是CEO,管全局
- NetworkIdentity 是员工工牌,证明你是谁
- NetworkBehaviour 是具体岗位职责,决定你能干什么
我见过最典型的错误是什么?有人把NetworkIdentity挂在UI Canvas上。结果客户端一连接,整个UI都同步到所有客户端去了,画面惨不忍睹。记住:只有游戏世界中的对象才需要NetworkIdentity,UI、管理器这类全局对象不需要。
2.5 创建第一个网络预制体
咱们来创建一个简单的玩家预制体,验证配置是否生效。
- 在Hierarchy创建一个Cube,命名为
Player - 给它挂上
NetworkIdentity组件 - 勾选
Local Player Authority(让客户端能控制自己的玩家) - 创建一个脚本
PlayerController.cs,继承NetworkBehaviour - 将Player拖入Project窗口,做成预制体
- 把预制体拖到NetworkManager的
Player Prefab槽中
// PlayerController.cs
using UnityEngine;
using Mirror;
public class PlayerController : NetworkBehaviour
{
void Update()
{
// 只有本地玩家才能控制
if (!isLocalPlayer) return;
float moveX = Input.GetAxis("Horizontal");
float moveZ = Input.GetAxis("Vertical");
transform.Translate(new Vector3(moveX, 0, moveZ) * Time.deltaTime * 5f);
}
}
isLocalPlayer 是NetworkBehaviour提供的属性。它判断当前脚本是否属于本地玩家。没有这个判断,所有客户端都会控制所有玩家对象——那画面太美我不敢看。
2.6 测试网络连接
配置完成后,咱们来测试一下:
- 点击Play运行游戏
- 点击HUD上的
Host (Server + Client)按钮 - 你应该能看到一个Cube出现在场景中
- 按WASD键,Cube应该能移动
如果想测试真正的网络连接:
- Build一个客户端版本(File → Build Settings)
- 在编辑器中运行Host
- 打开客户端版本,点击
Client连接 - 两个窗口应该都能看到Cube,且各自控制自己的
2.7 本章小结
到这步,咱们已经完成了:
- 创建了Unity项目并导入了Mirror
- 配置了NetworkManager的核心参数
- 理解了NetworkManager → NetworkIdentity → NetworkBehaviour的层级关系
- 创建了第一个网络预制体并验证了连接
嗯,地基算是打好了。下一章咱们会深入网络同步的核心——SyncVar和Command/Rpc。到时候你会发现,今天搭的这个架子有多重要。
对了,如果你在配置过程中遇到任何问题,别急着翻文档。先检查一下NetworkManager的Player Prefab有没有拖进去——我敢打赌,80%的"连不上"问题都是因为这个。