Differences between revisions 11 and 30 (spanning 19 versions)
Revision 11 as of 2021-03-01 12:18:22
Size: 598
Editor: zbjxb
Comment:
Revision 30 as of 2021-03-01 13:15:12
Size: 4857
Editor: zbjxb
Comment:
Deletions are marked like this. Additions are marked like this.
Line 10: Line 10:
= How to add replication to a base Actor = <<Anchor(#1)>> = #1 and #3 =
<<Anchor(1)>>How to add replication to a base Actor <<BR>>
<<Anchor(3)>>How to add replication to '''variables'''

{{{#!highlight C++
////////////////////////////
// ThirdPersonMPCharacter.h
////////////////////////////
/** The player's current health. When reduced to 0, they are considered dead.*/
UPROPERTY(ReplicatedUsing=OnRep_CurrentHealth)
float CurrentHealth;

/** RepNotify for changes made to current health.*/
UFUNCTION()
void OnRep_CurrentHealth();

/** Property replication */
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
}}}

{{{#!highlight C++
////////////////////////////
// ThirdPersonMPCharacter.cpp
////////////////////////////

//////////////////////////////////////////////////////////////////////////
// Replicated Properties

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

    //Replicate current health.
    DOREPLIFETIME(AThirdPersonMPCharacter, CurrentHealth);
}
}}}

= #4 and #6 =
<<Anchor(4)>>How to use '''!RepNotifies''' when a variable changes<<BR>>
<<Anchor(6)>>How to check an Actor's '''Network Role''' in order to filter calls that are performed within a function

{{{#!highlight C++
////////////////////////////
// ThirdPersonMPCharacter.h
////////////////////////////

/** Response to health being updated. Called on the server immediately after modification, and on clients in response to a RepNotify*/
void OnHealthUpdate();
}}}

{{{#!highlight C++
////////////////////////////
// ThirdPersonMPCharacter.cpp
////////////////////////////

void AThirdPersonMPCharacter::OnHealthUpdate()
{
    //Client-specific functionality
    if (IsLocallyControlled())
    {
        FString healthMessage = FString::Printf(TEXT("You now have %f health remaining."), CurrentHealth);
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, healthMessage);

        if (CurrentHealth <= 0)
        {
            FString deathMessage = FString::Printf(TEXT("You have been killed."));
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, deathMessage);
        }
    }

    //Server-specific functionality
    if (GetLocalRole() == ROLE_Authority)
    {
        FString healthMessage = FString::Printf(TEXT("%s now has %f health remaining."), *GetFName().ToString(), CurrentHealth);
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, healthMessage);
    }

    //Functions that occur on all machines.
    /*
        Any special functionality that should occur as a result of damage or death should be placed here.
    */
}

void AThirdPersonMPCharacter::OnRep_CurrentHealth()
{
    OnHealthUpdate();
}
}}}

= TakeDamage from APawn =

{{{#!highlight C++
////////////////////////////
// ThirdPersonMPCharacter.h
////////////////////////////

/** Setter for Current Health. Clamps the value between 0 and MaxHealth and calls OnHealthUpdate. Should only be called on the server.*/
UFUNCTION(BlueprintCallable, Category="Health")
void SetCurrentHealth(float healthValue);

/** Event for taking damage. Overridden from APawn.*/
UFUNCTION(BlueprintCallable, Category = "Health")
float TakeDamage( float DamageTaken, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser ) override;
}}}

{{{#!highlight C++
////////////////////////////
// ThirdPersonMPCharacter.cpp
////////////////////////////

void AThirdPersonMPCharacter::SetCurrentHealth(float healthValue)
{
    if (GetLocalRole() == ROLE_Authority)
    {
        CurrentHealth = FMath::Clamp(healthValue, 0.f, MaxHealth);
        OnHealthUpdate();
    }
}

float AThirdPersonMPCharacter::TakeDamage(float DamageTaken, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
    float damageApplied = CurrentHealth - DamageTaken;
    SetCurrentHealth(damageApplied);
    return damageApplied;
}
}}}
注意:!SetCurrentHealth函数里也调用了!OnHealthUpdate,这是为了确保server和client同时都能调到该函数进而保持Health值一致。这个调用是必须的,因为'''server不会收到!RepNotify'''。

原文

  • How to add replication to a base Actor #1

  • How to take advantage of Movement Components in a network game #2

  • How to add replication to variables #3

  • How to use RepNotifies when a variable changes #4

  • How to use Remote Procedure Calls (RPCs) in C++ #5

  • How to check an Actor's Network Role in order to filter calls that are performed within a function #6

#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)