[[https://docs.unrealengine.com/en-US/InteractiveExperiences/Networking/QuickStart/index.html | 原文]] * 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''' {{{#!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& OutLifetimeProps) const override; }}} {{{#!highlight C++ //////////////////////////// // ThirdPersonMPCharacter.cpp //////////////////////////// ////////////////////////////////////////////////////////////////////////// // Replicated Properties void AThirdPersonMPCharacter::GetLifetimeReplicatedProps(TArray & OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); //Replicate current health. DOREPLIFETIME(AThirdPersonMPCharacter, CurrentHealth); } }}} = #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 {{{#!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'''。