MultiplayerSynchronizer
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — MultiplayerSynchronizer
MultiplayerSynchronizer
节点继承关系
继承链:Node → MultiplayerSynchronizer
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
自动同步节点属性的"广播员"——服务器上角色的坐标每帧都在变,Synchronizer 自动把最新坐标广播给所有人。
打个比方:MultiplayerSpawner 负责"生"和"死"(节点出现/消失),MultiplayerSynchronizer 负责"动"(节点属性变化同步)。两者通常配合使用——就像一个管"招新员工",一个管"实时汇报员工在干什么"。
使用频率:★★ 偶尔使用——几乎每个多人游戏都会用到。
节点用途
- 同步玩家位置和旋转,让所有人看到角色在移动
- 同步血量、状态等游戏数据
- 同步自定义变量(如输入方向、动画状态)
- 控制同步频率,优化网络带宽
使用场景
典型场景
- 多人射击:同步所有玩家的位置和朝向
- 多人 RPG:同步角色的血量、装备状态
- 赛车游戏:同步车辆位置、速度
不适用场景
- 需要同步生成/删除节点 → 使用 MultiplayerSpawner
- 需要调用远程函数(如"开火"指令) → 使用 RPC(
@rpc装饰器) - 需要和 Web 服务器通信 → 使用 HTTPRequest
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| MultiplayerSpawner | 同步生成需要被同步属性的节点 | 推荐 |
| SceneReplicationConfig | 配置哪些属性需要同步 | 必需 |
| ENetMultiplayerPeer | 建立网络连接 | 必需 |
典型节点树:
Player (CharacterBody3D)
├── CollisionShape3D
├── MeshInstance3D
└── MultiplayerSynchronizer
└── RootPath = ".."(指向 Player 自身)
└── ReplicationConfig = 配置要同步的属性列表生效必备素材/资源
| 资源 | 类型 | 说明 |
|---|---|---|
| SceneReplicationConfig | 资源 | 配置哪些属性需要同步、同步模式(OnChange / Always),可通过编辑器或代码创建 |
节点属性与信号
同步配置
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
ReplicationConfig | SceneReplicationConfig | null | — | 要同步哪些属性的配置(核心属性) |
RootPath | NodePath | .. | — | 要同步属性的节点路径(默认是父节点) |
同步间隔
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
SyncInterval | float | 0.0 | — | 同步间隔(秒),0 = 每帧同步 |
DeltaInterval | float | 1.0 | — | 增量同步间隔(秒),仅同步变化的属性 |
ReplicationInterval | float | 0.0 | — | 完整同步间隔(秒),发送全部属性的完整快照 |
可见性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
VisibilityProcessMode | 枚举 | Inherit | — | 可见性更新模式:Inherit(继承)/ Physics(物理帧)/ Idle(空闲帧) |
VisibilityUpdateMode | 枚举 | Auto | — | 可见性更新时机:Auto(自动)/ Never(从不)/ Always(总是) |
PublicVisibility | bool | false | — | 是否公开可见性信息 |
信号
| 信号 | 触发时机 | 继承自 | 说明 |
|---|---|---|---|
synchronized() | 接收到同步数据并更新属性后 | — | 每次从服务器收到同步数据并应用到节点时触发 |
visibility_changed() | 可见性发生变化时 | — | 当某个远端客户端开始/停止接收此同步器的数据时触发 |
delta_synchronized(properties) | 接收到增量同步数据时 | — | 参数为本次变化的属性名称列表 |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
GetRootPath() | NodePath | 获取要同步属性的节点路径 |
SetRootPath(path) | void | 设置要同步属性的节点路径 |
GetReplicationConfig() | SceneReplicationConfig | 获取同步配置对象 |
SetReplicationConfig(config) | void | 设置同步配置对象 |
IsMultiplayerAuthority() | bool | 当前是否是权威端(决定能不能修改被同步的属性) |
GetVisibilityPeers() | int[] | 获取当前能"看到"此同步器的远端客户端 ID 列表 |
代码示例
C
using Godot;
/// <summary>
/// 玩家同步控制器——演示如何配置 MultiplayerSynchronizer
/// 节点结构:Player (CharacterBody3D) + MultiplayerSynchronizer(子节点)
/// </summary>
public partial class PlayerSync : MultiplayerSynchronizer
{
public override void _Ready()
{
var config = new SceneReplicationConfig();
// 添加要同步的属性(属性路径,同步模式)
// ReplicationMode.OnChange = 仅在属性变化时同步(省带宽)
// ReplicationMode.Always = 每次同步都发送(适合频繁变化的值)
config.AddProperty("position", SceneReplicationConfig.ReplicationMode.OnChange);
config.AddProperty("rotation", SceneReplicationConfig.ReplicationMode.OnChange);
config.AddProperty(":health", SceneReplicationConfig.ReplicationMode.OnChange);
config.AddProperty(":input_direction", SceneReplicationConfig.ReplicationMode.OnChange);
ReplicationConfig = config;
}
/// <summary>
/// 每帧更新玩家输入方向——只有权威端(服务器或本机玩家)才能修改
/// </summary>
public override void _Process(double delta)
{
// 非权威端不处理输入,只接受同步数据
if (!IsMultiplayerAuthority())
return;
// 读取玩家输入并更新属性
Vector2 input = Input.GetVector("move_left", "move_right", "move_forward", "move_back");
Set("input_direction", input);
}
}GDScript
# 玩家同步控制器——演示如何配置 MultiplayerSynchronizer
# 节点结构:Player (CharacterBody3D) + MultiplayerSynchronizer(子节点)
extends MultiplayerSynchronizer
func _ready() -> void:
var config = SceneReplicationConfig.new()
# 添加要同步的属性(属性路径,同步模式)
# REPLICATION_MODE_ON_CHANGE = 仅在属性变化时同步(省带宽)
# REPLICATION_MODE_ALWAYS = 每次同步都发送(适合频繁变化的值)
config.add_property("position", SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE)
config.add_property("rotation", SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE)
config.add_property(":health", SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE)
config.add_property(":input_direction", SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE)
replication_config = config
## 每帧更新玩家输入方向——只有权威端(服务器或本机玩家)才能修改
func _process(delta: float) -> void:
# 非权威端不处理输入,只接受同步数据
if not is_multiplayer_authority():
return
# 读取玩家输入并更新属性
var input := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
set("input_direction", input)属性路径的写法
- 不带冒号前缀(如
position):同步的是根节点(RootPath)的内置属性 - 带冒号前缀(如
:health):同步的是根节点脚本中定义的变量
冒号 : 是 Godot 用来区分"节点自身属性"和"脚本变量"的标记。
OnChange vs Always
- OnChange(按需同步):属性值发生变化时才发送数据。适合位置、旋转、血量等"偶尔变"的值。省带宽。
- Always(总是同步):每次同步周期都发送数据。适合输入方向等"每帧都在变"的值。数据量大,但保证最新。
