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.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。