原文

#1 and #3

How to add replication to a base Actor
How to add replication to variables

   1 ////////////////////////////
   2 // ThirdPersonMPCharacter.h
   3 ////////////////////////////
   4 /** The player's current health. When reduced to 0, they are considered dead.*/
   5 UPROPERTY(ReplicatedUsing=OnRep_CurrentHealth)
   6 float CurrentHealth;
   7 
   8 /** RepNotify for changes made to current health.*/
   9 UFUNCTION()
  10 void OnRep_CurrentHealth();
  11 
  12 /** Property replication */
  13 void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

   1 ////////////////////////////
   2 // ThirdPersonMPCharacter.cpp
   3 ////////////////////////////
   4 
   5 //////////////////////////////////////////////////////////////////////////
   6 // Replicated Properties
   7 
   8 void AThirdPersonMPCharacter::GetLifetimeReplicatedProps(TArray <FLifetimeProperty> & OutLifetimeProps) const
   9 {
  10     Super::GetLifetimeReplicatedProps(OutLifetimeProps);
  11 
  12     //Replicate current health.
  13     DOREPLIFETIME(AThirdPersonMPCharacter, CurrentHealth);
  14 }

#4 and #6

How to use RepNotifies when a variable changes
How to check an Actor's Network Role in order to filter calls that are performed within a function

   1 ////////////////////////////
   2 // ThirdPersonMPCharacter.h
   3 ////////////////////////////
   4 
   5 /** Response to health being updated. Called on the server immediately after modification, and on clients in response to a RepNotify*/
   6 void OnHealthUpdate();

   1 ////////////////////////////
   2 // ThirdPersonMPCharacter.cpp
   3 ////////////////////////////
   4 
   5 void AThirdPersonMPCharacter::OnHealthUpdate()
   6 {
   7     //Client-specific functionality
   8     if (IsLocallyControlled())
   9     {
  10         FString healthMessage = FString::Printf(TEXT("You now have %f health remaining."), CurrentHealth);
  11         GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, healthMessage);
  12 
  13         if (CurrentHealth <= 0)
  14         {
  15             FString deathMessage = FString::Printf(TEXT("You have been killed."));
  16             GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, deathMessage);
  17         }
  18     }
  19 
  20     //Server-specific functionality
  21     if (GetLocalRole() == ROLE_Authority)
  22     {
  23         FString healthMessage = FString::Printf(TEXT("%s now has %f health remaining."), *GetFName().ToString(), CurrentHealth);
  24         GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, healthMessage);
  25     }
  26 
  27     //Functions that occur on all machines. 
  28     /*  
  29         Any special functionality that should occur as a result of damage or death should be placed here. 
  30     */
  31 }
  32 
  33 void AThirdPersonMPCharacter::OnRep_CurrentHealth()
  34 {
  35     OnHealthUpdate();
  36 }

TakeDamage from APawn

   1 ////////////////////////////
   2 // ThirdPersonMPCharacter.h
   3 ////////////////////////////
   4 
   5 /** Setter for Current Health. Clamps the value between 0 and MaxHealth and calls OnHealthUpdate. Should only be called on the server.*/
   6 UFUNCTION(BlueprintCallable, Category="Health")
   7 void SetCurrentHealth(float healthValue);
   8 
   9 /** Event for taking damage. Overridden from APawn.*/
  10 UFUNCTION(BlueprintCallable, Category = "Health")
  11 float TakeDamage( float DamageTaken, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser ) override;

   1 ////////////////////////////
   2 // ThirdPersonMPCharacter.cpp
   3 ////////////////////////////
   4 
   5 void AThirdPersonMPCharacter::SetCurrentHealth(float healthValue)
   6 {
   7     if (GetLocalRole() == ROLE_Authority)
   8     {
   9         CurrentHealth = FMath::Clamp(healthValue, 0.f, MaxHealth);
  10         OnHealthUpdate();
  11     }
  12 }
  13 
  14 float AThirdPersonMPCharacter::TakeDamage(float DamageTaken, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
  15 {
  16     float damageApplied = CurrentHealth - DamageTaken;
  17     SetCurrentHealth(damageApplied);
  18     return damageApplied;
  19 }

注意:SetCurrentHealth函数里也调用了OnHealthUpdate,这是为了确保server和client同时都能调到该函数进而保持Health值一致。这个调用是必须的,因为server不会收到RepNotify

UE4-Networking-And-Multiplayer/MultiplayerProgrammingQuickStart (last edited 2021-03-01 13:15:12 by zbjxb)