什么是复制?
复制就是服务器发送信息给客户端,以保持两边的数据一致.
既然是是保证两边的数据一致,就有一个前提条件,就是该Actor对象必须同时存在于服务器和客户端.如此,只存在于服务器的GameMode和只存在于客户端的AHUD都不能复制.
还有一点,并不是只能复制Actor,如果要复制UObject对象,则需要将其放入Actor中,比如UActorComponent就是一个最好的例子.
如何使用复制?
设置Actor的'bReplicates’属性为真.
蓝图中:
C++中:
ATestCharacter::ATestCharacter(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { bReplicates = true; bReplicateMovement = true; }
注意:'bReplicates’设置为True之后,当且仅当Actor是在服务器上生成时,才会复制到客户端.在客户端生成时,无法复制到服务器的.服务器具有权威性,一切以它为准.
启用Actor复制之后会复制那些内容
复制功能 | 说明 |
创建和销毁 | 服务器上生成复制Actor的授权版本时,其会在所有连接客户端上自动生成远程代理。其之后会将信息复制到这些远程代理。若销毁授权Actor,则将自动销毁所有连接客户端上的远程代理。 |
移动复制 | 若授权Actor启用了 复制移动,或将C++中的 bReplicateMovement 设为 true ,其将自动复制位置、旋转和速度。 |
变量复制 | 在指定为复制变量的值变更时,其将自动从授权Actor复制到其远程代理。 |
组件复制 | Actor组件复制为其所属Actor的一部分。组件内指定为复制变量将复制,而组件内调用的RPC将与Actor类中调用的RPC保持一致。 |
远程过程调用(RPC) | RPC是传输到网络游戏中特定机器的特殊函数。无论初始调用RPC的是哪台机器,其的实现仅在目标机器上运行。此类RPC可指定为服务器(仅在服务器上运行)、客户端(仅在Actor的拥有客户端上运行)或NetMulticast(在连接会话的所有机器上运行,包括服务器)。 |
Actor、Pawn和角色的部分常用功能不会复制:
- 骨架网格体 和 静态网格体 组件
- 材质
- 动画蓝图
- 粒子系统
- 音效发射器
- 物理对象
此类项目均在所有客户端上单独运行。但是,若复制驱动此类视觉元素的变量,则可确保所有客户端都具有相同信息,从而以大致相同的方式进行模拟。
属性复制
在蓝图中的Actor属性上勾选复制之后,变量上会有白球标记:
此时,变量将会在一定的条件下能够复制.具体条件下面再说.
在C++,中看起来会麻烦些,但是可以设置复制的条件:
// Create replicated health variable UPROPERTY(Replicated) float Health;
在cpp文件中:
void ATestPlayerCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); // Here we list the variables we want to replicate DOREPLIFETIME(ATestPlayerCharacter, Health); }
设置复制的条件:
// Replicates the Variable only to the Owner of this Object/Class DOREPLIFETIME_CONDITION(ATestPlayerCharacter, Health, COND_OwnerOnly);
复制的条件
Condition | Description |
COND_InitialOnly | 此属性只会尝试发送初始组 |
COND_OwnerOnly | 该属性只会发送给 Actor 的所有者 |
COND_SkipOwner | 此属性发送到除所有者之外的所有连接 |
COND_SimulatedOnly | 该属性只会发送给 simulated Actors |
COND_AutonomousOnly | 该属性只会发送给 autonomous Actors |
COND_SimulatedOrPhysics | 该属性只会发送给 simulated OR bRepPhysics Actor |
COND_InitialOrOwner | 此属性只会尝试发送初始组或者发送给 Actor 的所有者 |
COND_Custom | 自定义条件,可以通过SetCustomIsActiveOverride打开或者关闭 |
关于Actor owner和Simulated Actor,Autonomous Actors将在后面的章节解释.
回调复制
复制变量的另一种方法是将其标记为“ReplicatedUsing”.在蓝图中,这称为“RepNotify”.它允许指定一个函数,当变量的新值复制到客户端时,该函数将在客户端上调用.
在蓝图中,一旦在“复制”下拉菜单中选择“RepNotify”,就会自动创建此函数:
在C++中:
// Create RepNotify Health variable UPROPERTY(ReplicatedUsing=OnRep_Health) float Health; // Create OnRep function | UFUNCTION() Macro is important! | Doesn't need to be virtual UFUNCTION() virtual void OnRep_Health();
void ATestCharacter::OnRep_Health() { if (Health <= 0.f) { PlayDeathAnimation(); } }
回调复制中 C++ 和蓝图之间的差异
这里需要注意的是,C++ 和蓝图处理 RepNotify 的方式略有不同.在 C++ 中,RepNotify 函数仅调用客户端.
当服务器改变值并需要调用OnRep函数时,您需要在调整变量后手动调用它.这是因为 OnRep 函数是变量复制到客户端时的回调.一般来说,OnRep只是一个回调通知,你可以在客户端中改变这个变量与服务器的值一致,也可以改成其他值.如果改为其他值时,也需要服务器变更值时.就不一样了,因为在C++中这个函数不会在服务器调用.所以需要在调整变量后手动调用它.
然而,在蓝图中,OnRep 函数将调用客户端和服务器。这是因为 OnRep 的 BP 版本是“属性更改”回调。这意味着该函数也将调用服务器,而且如果客户端在本地更改变量,也会调用客户端。