4、网络同步基础(Transform同步):使用NetworkTransform、同步频率与插值、处理网络延迟
好,咱们今天聊一个很实在的话题——Transform同步。
说白了,就是让所有玩家看到的物体位置、旋转、缩放保持一致。你想想看,一个FPS游戏里,敌人明明在你屏幕里站着,结果你开枪打空气,因为在他自己的世界里早就跑开了。这就是同步没做好。
4.1 NetworkTransform:开箱即用的同步组件
Unity Netcode 给我们提供了一个好东西——NetworkTransform。我个人习惯叫它「NT」。这东西就像个勤劳的快递员,不停地把物体的位置、旋转信息打包发出去。
用法很简单:
// 给物体挂上 NetworkObject + NetworkTransform
// 然后 spawn 它
GameObject go = Instantiate(prefab);
go.GetComponent<NetworkObject>().Spawn();
嗯,这里要注意:只有服务器有权修改NT的Transform。客户端想改?得先申请权限。我在项目中遇到过新手直接把客户端的位置赋值给NT,结果服务器根本不认,角色卡在原地不动。
核心原则:谁拥有权威(Authority),谁就能改Transform。默认是服务器拥有所有物体的权威。
4.2 同步频率:别让网络变成水管
NT默认每帧都发数据?那你的带宽就炸了。实际上,我们得控制发送频率。
看这个参数:
// 在 NetworkTransform 组件上
// Sync Interval = 0.1 表示每100ms发一次
// 也就是每秒10次
为什么是10次?我做过测试:
| 同步频率 | 带宽消耗 | 平滑度 | 适用场景 |
|---|---|---|---|
| 30次/秒 | 高 | 非常平滑 | 局域网、高速竞技 |
| 10次/秒 | 中 | 良好 | 一般网络游戏 |
| 5次/秒 | 低 | 有卡顿感 | 休闲、回合制 |
我个人建议:先设10次/秒。如果感觉卡顿,再往上调。别一上来就30次,你想想看,100个玩家每人每秒发30次位置更新,服务器扛不住的。
小技巧:动态调整频率。角色静止时降到2次/秒,移动时升到15次/秒。我在项目中用这个方案,带宽直接省了60%。
4.3 插值:让运动看起来丝滑
频率设低了,位置更新就断断续续的。怎么办?插值。
NT自带两种模式:
- Interpolate(插值):在两次更新之间,平滑过渡。适合大多数情况。
- Extrapolate(外推):根据上次的运动趋势,预测下一个位置。适合高速移动的物体。
我举个例子:
// 在 NetworkTransform 上设置
// Interpolate = true
// 这样客户端收到位置A和位置B之间,会自动补帧
为什么会这样?因为网络包不是均匀到达的。有时候100ms来一个,有时候150ms。插值就是让物体在这段时间里「假装」在移动,而不是瞬移。
我曾经做过一个赛车游戏,没开插值前,对手的车像在跳帧动画。开了之后,虽然实际位置有误差,但视觉上完全能接受。
注意:插值会引入延迟。你看到的位置其实是100ms前的。对于需要精确碰撞检测的游戏(比如格斗),要谨慎使用。
4.4 处理网络延迟:别让玩家骂娘
延迟是绕不开的坎。你按了W,角色0.5秒后才动,玩家早卸载游戏了。
我的处理思路分三步:
- 客户端预测:客户端收到输入后,立即执行,不等服务器确认。
- 服务器权威:服务器最终决定正确位置,并纠正客户端。
- 延迟补偿:服务器回滚到玩家发出输入的时刻,进行判定。
代码示例(简化版):
// 客户端:立即移动
void Update() {
if (IsOwner) {
float move = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
transform.position += Vector3.right * move;
// 同时发送输入给服务器
SendInputToServer(move);
}
}
// 服务器:收到输入后验证
void OnServerReceivedInput(float move, ulong clientId) {
// 根据输入计算预期位置
Vector3 expectedPos = GetPlayer(clientId).transform.position
+ Vector3.right * move;
// 如果客户端位置偏差太大,纠正它
if (Vector3.Distance(actualPos, expectedPos) > 0.5f) {
SendCorrection(clientId, expectedPos);
}
}
嗯,这里有个坑。我曾经做过一个项目,客户端预测做得太激进,导致角色在服务器纠正时「瞬移」回来。玩家反馈说「我的角色被鬼拉回去了」。后来我加了平滑纠正,用Lerp慢慢过渡,体验就好了很多。
避坑指南:我曾经把同步频率设成0.01秒(100次/秒),结果服务器CPU直接飙到90%。后来改成动态频率,根据物体移动速度自动调整,问题就解决了。
4.5 实战建议:从简单开始
如果你刚开始做联机,别一上来就搞客户端预测、延迟补偿这些高级玩意。我建议:
- 先用NT默认设置,跑通同步流程
- 观察带宽和延迟,调整频率
- 加上插值,改善视觉体验
- 最后再考虑预测和补偿
说白了,Transform同步就是个「平衡艺术」。你要在带宽、延迟、平滑度之间找平衡点。没有完美的方案,只有适合你游戏的方案。
我记得第一次做联机时,光调同步参数就花了一周。但当你看到所有玩家的角色都能流畅地一起跑动时,那种成就感,嗯,值得。
最后一个小建议:用Unity的Profiler监控网络数据。看看哪个物体在疯狂发数据,哪个物体同步延迟高。数据不会骗人。