必须显式启用 breplicates,否则任何 uproperty(replicated) 都不会同步;需在构造函数设 breplicates = true,并在头文件用 uproperty(replicated) 声明变量,如 float health;uobject 指针需加 replicatedusing=onrep_xxx 并实现回调;客户端只接收服务器更新,且须在 hasauthority() 分支修改属性,配合 onrep_ 回调刷新逻辑。

必须显式启用 bReplicates,否则任何 UPROPERTY(replicated) 都不会同步 —— 这是 90% 新手卡住的第一步。
如何声明一个可同步的属性
UE 的属性同步不是“加个宏就自动走”,它依赖两层开关:Actor 级别的复制总开关 + 属性级的 replicated 标记。
- 在 C++ 头文件中用
UPROPERTY(replicated)声明变量,例如:UPROPERTY(replicated) float Health; - 必须在构造函数中设置
bReplicates = true;,否则该 Actor 完全不进入复制队列 - 若该属性是 UObject 指针(如
UAnimInstance*),需额外加ReplicatedUsing=OnRep_XXX并实现回调函数,否则只同步指针地址、不保证对象已加载 - 基础类型(
float、int32、bool)和FVector可直接同步;但TSubclassOf<aactor></aactor>等模板类型需配合ReplicatedUsing或改用UClass*才能可靠传输
为什么修改了属性客户端没反应
常见现象是服务器改了 Health,客户端值不变,或只在重连后才更新。根本原因往往不在代码写法,而在同步时机和所有权逻辑。
- 客户端只能接收来自服务器的更新,
ROLE_Authority必须在 Server 上 —— 如果你在客户端调用SetHealth(),它不会触发复制,除非你手动调用ForceNetUpdate() - 属性变更必须发生在 Server 的
Authority分支下,典型写法:if (HasAuthority()) { Health = NewValue; } - 没有
OnRep_Health回调?那客户端即使收到了新值,也不会自动刷新 UI 或播放受伤动画 —— 回调函数必须声明为UFUNCTION()且参数匹配(如void OnRep_Health();) - 若该 Actor 是动态生成(如
GetWorld()->SpawnActor<aweapon>()</aweapon>),确保 Spawn 时传入了有效的FActorSpawnParameters,尤其是bRemoteOwned和Owner设置,否则客户端可能收不到完整复制流
NetUpdateFrequency 和 NetPriority 怎么调才不翻车
这两个参数不常改,但一旦出问题很难定位。它们影响的是“是否被选中复制”,而不是“复制内容是否正确”。
-
NetUpdateFrequency默认是 100.0(每秒最多同步 100 次),对频繁变化的属性(如角色位置)够用;但对血量这种低频变化属性,设成 1.0 更省带宽,且避免因帧率抖动导致重复同步 -
NetPriority默认是 1.0,Pawn类默认为 3.0 —— 在网络拥塞时,引擎会优先丢弃低优先级 Actor 的更新;如果你自定义了一个关键 UI Actor,却忘了提高它的NetPriority,它可能永远收不到更新 - 不要在运行时频繁修改这两个值,它们只在 Actor 初始化时注册进 NetDriver 的调度表;运行时改了也不会立刻生效,得等下次
NextUpdateTime重新计算 - 调试时可用控制台命令
net.DumpReplication 1查看当前哪些 Actor 正在排队等待同步,结合stat net观察实际带宽占用
真正容易被忽略的是:UPROPERTY(replicated) 的变量在客户端是只读的,直接赋值不会触发 OnRep_ 回调,也不会同步回服务端 —— 即使你用了 FORCEINLINE 或 const_cast 绕过编译检查,运行时行为也不受保障。同步必须走引擎的复制管道,别试图“手动模拟”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











