UE4 C++项目中的同步案例

属性复制

.h文件:

virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

UPROPERTY(Replicated)
bool bAiming;

UPROPERTY(ReplicatedUsing = OnRep_EquippedWeapon)
AWeapon* EquippedWeapon;

UFUNCTION()
void OnRep_EquippedWeapon();

.cpp文件:

void UCombatComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    
    
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(UCombatComponent, EquippedWeapon);
	DOREPLIFETIME(UCombatComponent, bAiming);
}

void UCombatComponent::OnRep_EquippedWeapon()
{
    
    
	if(EquippedWeapon && Character)
	{
    
    
		EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
		AttachActorToRightHand(EquippedWeapon);
		Character->GetCharacterMovement()->bOrientRotationToMovement = false;
		Character->bUseControllerRotationYaw = true;
		PlayEquipWeaponSound(EquippedWeapon);
		EquippedWeapon->SetHUDAmmo();
	}
}

启用属性复制的变量需重写GetLifetimeReplicatedProps函数,告知UE4这些变量需要复制。属性复制可以是单纯的对这个变量进行复制,如上面的bAiming变量,通过在上方添加 UPROPERTY(Replicated) 实现,这个变量可以传给AnimInstance,AnimInstance中会根据bAiming的值决定是否在瞄准状态。通过将这个变量设为复制,本地客户端在瞄准时会播放瞄准动画,其他人也会同步显示瞄准动画。

另一种是带有通知的属性复制,如上面的EquippedWeapon变量。在变量上方添加 UPROPERTY(ReplicatedUsing = OnRep_EquippedWeapon) 就会在EquippedWeapon变量发生改变时执行OnRep_EquippedWeapon函数,执行一些额外的操作。

RPC

.h文件:

UFUNCTION(Server, Reliable)
void ServerFire(const FVector_NetQuantize& TraceHitTarget);

UFUNCTION(NetMulticast, Reliable)
void MulticastFire(const FVector_NetQuantize& TraceHitTarget);

.cpp文件:

void UCombatComponent::Fire()
{
    
    
	if(CanFire())
	{
    
    
		ServerFire(HitTarget);
		if(EquippedWeapon)
		{
    
    
			CrosshairShootingFactor = 1.f;
		}
		StartFireTimer();
	}
}

void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
    
    
	MulticastFire(TraceHitTarget);
}

void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
    
    
	if(EquippedWeapon == nullptr) return;
	if(Character && CombatState == ECombatState::ECS_Reloading && EquippedWeapon->GetWeaponType() == EWeaponType::EWT_Shotgun)
	{
    
    
		Character->PlayFireMontage(bAiming);
		EquippedWeapon->Fire(TraceHitTarget);
		CombatState = ECombatState::ECS_Unoccupied;
		return;
	}
	if(Character && CombatState == ECombatState::ECS_Unoccupied)
	{
    
    
		Character->PlayFireMontage(bAiming);
		EquippedWeapon->Fire(TraceHitTarget);
	}
}

RPC有Multicast、Run On Server、Run On owning Client几种,我的项目中Run On owning Client没有用到,这里就只展示另外两种。RPC函数上方需声明这个函数是哪一种RPC,在.cpp文件中实现时,函数名后面要加上_Implementation,告诉编译器这是个RPC函数。上面代码的逻辑是,本地在开火时,执行Fire()函数,检测是否达成开火的条件,达成的话执行ServerFire()函数,这是一个服务器RPC,会在服务器上执行。ServerFire()中又执行了MulticastFire()函数,这是一个多播RPC,由服务器执行多播RPC的话,会同步在所有客户端上执行。因此经由上述代码,本地执行开火函数调用服务器RPC,服务器又调用多播RPC,实现了所有端同步执行开火逻辑。

猜你喜欢

转载自blog.csdn.net/weixin_47260762/article/details/127412966