6. 3D网络同步
2026/4/14大约 3 分钟
3D网络同步
你和朋友联机玩游戏时,你们各自的屏幕上看到的是同一场景——你在你这边往前走了一步,朋友那边也看到你的角色往前走了一步。这背后的技术就是"网络同步":把每个人的操作通过网络告诉其他人,让大家看到的游戏世界保持一致。
本章你将学到
- 状态同步和帧同步的区别与选择
- 插值与预测:让网络延迟不影响操作手感
- 3D 位置、旋转的同步方案
- 如何处理网络延迟和丢包
两种同步方式
状态同步
每个玩家只把自己的"状态"(位置、血量、朝向等)发给服务器,服务器再把结果广播给其他玩家。就像开会时每个人只汇报自己的工作进度,主持人汇总后通知所有人。
- 优点:数据量小,安全性好(玩家不能作弊改数据)
- 缺点:服务器逻辑复杂,需要权威服务器
- 适合:MMO、大逃杀等大量玩家的游戏
帧同步
每个玩家只发送自己的"操作"(按了什么键),所有玩家的游戏都接收相同的操作序列,各自本地计算结果。就像下棋,大家收到同一手棋的信息,各自在自己的棋盘上摆。
- 优点:服务器简单,只要转发操作
- 缺点:所有客户端必须算出完全相同的结果(浮点数精度问题很头疼)
- 适合:格斗、RTS 等需要精确判定的游戏
代码示例:简单的 3D 位置同步
以下示例展示如何用 Godot 的多人网络 API 同步角色位置(状态同步方式):
C#
using Godot;
public partial class NetworkPlayer : CharacterBody3D
{
private MultiplayerSynchronizer _synchronizer;
private Vector3 _syncPosition;
private float _interpolationFactor;
[Export]
public Vector3 SyncPosition
{
get => _syncPosition;
set
{
_syncPosition = value;
_interpolationFactor = 0;
}
}
public override void _Ready()
{
_synchronizer = GetNode<MultiplayerSynchronizer>("MultiplayerSynchronizer");
// 只有自己控制的角色才发送位置
_synchronizer.SetProcess(IsMultiplayerAuthority());
}
public override void _PhysicsProcess(double delta)
{
if (IsMultiplayerAuthority())
{
// 自己的角色:正常移动
var input = Input.GetVector("move_left", "move_right", "move_forward", "move_back");
Velocity = new Vector3(input.X, 0, input.Y) * 5.0f;
MoveAndSlide();
SyncPosition = GlobalPosition;
}
else
{
// 其他玩家的角色:平滑插值到同步位置
_interpolationFactor += (float)delta * 10.0f;
_interpolationFactor = Mathf.Min(_interpolationFactor, 1.0f);
GlobalPosition = GlobalPosition.Lerp(SyncPosition, _interpolationFactor);
}
}
}GDScript
extends CharacterBody3D
var synchronizer: MultiplayerSynchronizer
var sync_position: Vector3:
set(value):
sync_position = value
_interpolation_factor = 0.0
var _interpolation_factor: float = 0.0
func _ready():
synchronizer = $MultiplayerSynchronizer
# 只有自己控制的角色才发送位置
synchronizer.set_process(is_multiplayer_authority())
func _physics_process(delta):
if is_multiplayer_authority():
# 自己的角色:正常移动
var input = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
velocity = Vector3(input.x, 0, input.y) * 5.0
move_and_slide()
sync_position = global_position
else:
# 其他玩家的角色:平滑插值到同步位置
_interpolation_factor += delta * 10.0
_interpolation_factor = minf(_interpolation_factor, 1.0)
global_position = global_position.lerp(sync_position, _interpolation_factor)插值与预测
网络有延迟,你看到朋友的角色可能在"瞬移"。插值就是在两个收到的位置之间做平滑过渡,让移动看起来流畅。预测则是先在本地预测其他玩家的移动方向,等真正的数据到了再修正,减少"卡顿感"。
