完成复活逻辑
This commit is contained in:
@@ -5,9 +5,22 @@
|
||||
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "Abilities/GameplayAbility.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "Components/MainAbilitySystemComponent.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "GameplayEffect.h"
|
||||
#include "MainAttributeSet.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
FGameplayTag GetDeadTag()
|
||||
{
|
||||
return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead")));
|
||||
}
|
||||
}
|
||||
|
||||
// Sets default values
|
||||
ABotCharacter::ABotCharacter()
|
||||
@@ -30,6 +43,17 @@ void ABotCharacter::BeginPlay()
|
||||
InitAbilityActorInfo();
|
||||
}
|
||||
|
||||
void ABotCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
UnbindHealthChangedDelegate();
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
World->GetTimerManager().ClearTimer(RespawnTimer);
|
||||
}
|
||||
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
void ABotCharacter::PossessedBy(AController* NewController)
|
||||
{
|
||||
Super::PossessedBy(NewController);
|
||||
@@ -63,7 +87,9 @@ void ABotCharacter::InitAbilityActorInfo()
|
||||
return;
|
||||
}
|
||||
|
||||
UnbindHealthChangedDelegate();
|
||||
AbilitySystemComponent->InitAbilityActorInfo(this, this);
|
||||
BindHealthChangedDelegate();
|
||||
|
||||
if (HasAuthority())
|
||||
{
|
||||
@@ -72,6 +98,39 @@ void ABotCharacter::InitAbilityActorInfo()
|
||||
}
|
||||
}
|
||||
|
||||
void ABotCharacter::BindHealthChangedDelegate()
|
||||
{
|
||||
if (!AbilitySystemComponent || HealthChangedHandle.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HealthChangedHandle = AbilitySystemComponent
|
||||
->GetGameplayAttributeValueChangeDelegate(UMainAttributeSet::GetHealthAttribute())
|
||||
.AddUObject(this, &ThisClass::OnHealthChanged);
|
||||
}
|
||||
|
||||
void ABotCharacter::UnbindHealthChangedDelegate()
|
||||
{
|
||||
if (!AbilitySystemComponent || !HealthChangedHandle.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AbilitySystemComponent
|
||||
->GetGameplayAttributeValueChangeDelegate(UMainAttributeSet::GetHealthAttribute())
|
||||
.Remove(HealthChangedHandle);
|
||||
HealthChangedHandle.Reset();
|
||||
}
|
||||
|
||||
void ABotCharacter::OnHealthChanged(const FOnAttributeChangeData& Data)
|
||||
{
|
||||
if (HasAuthority() && Data.NewValue <= 0.f)
|
||||
{
|
||||
HandleDeath();
|
||||
}
|
||||
}
|
||||
|
||||
void ABotCharacter::GiveDefaultAbilities()
|
||||
{
|
||||
if (bHasGivenDefaultAbilities || !AbilitySystemComponent)
|
||||
@@ -110,3 +169,77 @@ void ABotCharacter::ApplyDefaultAttributeEffect()
|
||||
}
|
||||
}
|
||||
|
||||
void ABotCharacter::HandleDeath()
|
||||
{
|
||||
if (bHasHandledDeath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bHasHandledDeath = true;
|
||||
|
||||
if (AbilitySystemComponent)
|
||||
{
|
||||
AbilitySystemComponent->SetLooseGameplayTagCount(GetDeadTag(), 1, EGameplayTagReplicationState::TagOnly);
|
||||
}
|
||||
|
||||
MulticastHandleDeath();
|
||||
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
if (RespawnDelay <= 0.f)
|
||||
{
|
||||
HandleRespawn();
|
||||
}
|
||||
else
|
||||
{
|
||||
World->GetTimerManager().SetTimer(RespawnTimer, this, &ThisClass::HandleRespawn, RespawnDelay, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABotCharacter::MulticastHandleDeath_Implementation()
|
||||
{
|
||||
if (bHasNotifiedDeath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bHasNotifiedDeath = true;
|
||||
|
||||
GetCharacterMovement()->DisableMovement();
|
||||
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
GetMesh()->SetHiddenInGame(true, true);
|
||||
|
||||
BP_OnDeath();
|
||||
}
|
||||
|
||||
void ABotCharacter::HandleRespawn()
|
||||
{
|
||||
if (!HasAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AbilitySystemComponent)
|
||||
{
|
||||
AbilitySystemComponent->SetLooseGameplayTagCount(GetDeadTag(), 0, EGameplayTagReplicationState::TagOnly);
|
||||
|
||||
const float MaxHealth = AbilitySystemComponent->GetNumericAttribute(UMainAttributeSet::GetMaxHealthAttribute());
|
||||
AbilitySystemComponent->SetNumericAttributeBase(UMainAttributeSet::GetHealthAttribute(), MaxHealth);
|
||||
}
|
||||
|
||||
bHasHandledDeath = false;
|
||||
bHasNotifiedDeath = false;
|
||||
|
||||
MulticastRestoreRespawnState();
|
||||
}
|
||||
|
||||
void ABotCharacter::MulticastRestoreRespawnState_Implementation()
|
||||
{
|
||||
bHasNotifiedDeath = false;
|
||||
|
||||
GetCharacterMovement()->SetMovementMode(MOVE_Walking);
|
||||
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
|
||||
GetMesh()->SetHiddenInGame(false, true);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,21 @@
|
||||
|
||||
#include "MainAttributeSet.h"
|
||||
|
||||
#include "GameplayEffectExtension.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
FGameplayTag GetDeadTag()
|
||||
{
|
||||
return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead")));
|
||||
}
|
||||
}
|
||||
|
||||
UMainAttributeSet::UMainAttributeSet()
|
||||
{
|
||||
InitHealth(1000.f);
|
||||
InitMaxHealth(1000.f);
|
||||
InitHealth(50.f);
|
||||
InitMaxHealth(50.f);
|
||||
}
|
||||
|
||||
void UMainAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
|
||||
@@ -18,6 +27,47 @@ void UMainAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimePropert
|
||||
DOREPLIFETIME_CONDITION_NOTIFY(UMainAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
|
||||
}
|
||||
|
||||
void UMainAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
|
||||
{
|
||||
Super::PreAttributeChange(Attribute, NewValue);
|
||||
|
||||
if (Attribute == GetHealthAttribute())
|
||||
{
|
||||
NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
|
||||
}
|
||||
else if (Attribute == GetMaxHealthAttribute())
|
||||
{
|
||||
NewValue = FMath::Max(NewValue, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
void UMainAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
|
||||
{
|
||||
Super::PostGameplayEffectExecute(Data);
|
||||
|
||||
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
|
||||
{
|
||||
SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
|
||||
|
||||
if (GetHealth() <= 0.f)
|
||||
{
|
||||
if (UAbilitySystemComponent* ASC = GetOwningAbilitySystemComponent())
|
||||
{
|
||||
AActor* OwningActor = ASC->GetOwnerActor();
|
||||
if (OwningActor && OwningActor->HasAuthority())
|
||||
{
|
||||
ASC->SetLooseGameplayTagCount(GetDeadTag(), 1, EGameplayTagReplicationState::TagOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Data.EvaluatedData.Attribute == GetMaxHealthAttribute())
|
||||
{
|
||||
SetMaxHealth(FMath::Max(GetMaxHealth(), 0.f));
|
||||
SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
|
||||
}
|
||||
}
|
||||
|
||||
void UMainAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const
|
||||
{
|
||||
GAMEPLAYATTRIBUTE_REPNOTIFY(UMainAttributeSet, Health, OldHealth);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "AbilitySystemInterface.h"
|
||||
#include "Engine/TimerHandle.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "BotCharacter.generated.h"
|
||||
|
||||
@@ -11,6 +12,7 @@ class UAbilitySystemComponent;
|
||||
class UAttributeSet;
|
||||
class UGameplayAbility;
|
||||
class UGameplayEffect;
|
||||
struct FOnAttributeChangeData;
|
||||
|
||||
UCLASS()
|
||||
class PVPDEMO_API ABotCharacter : public ACharacter, public IAbilitySystemInterface
|
||||
@@ -29,6 +31,7 @@ public:
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="GAS")
|
||||
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;
|
||||
@@ -42,6 +45,12 @@ protected:
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="GAS")
|
||||
TSubclassOf<UGameplayEffect> DefaultAttributeEffect;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Respawn", meta=(ClampMin="0", Units="s"))
|
||||
float RespawnDelay = 2.f;
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Death")
|
||||
void BP_OnDeath();
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
@@ -51,9 +60,24 @@ public:
|
||||
|
||||
private:
|
||||
void InitAbilityActorInfo();
|
||||
void BindHealthChangedDelegate();
|
||||
void UnbindHealthChangedDelegate();
|
||||
void OnHealthChanged(const FOnAttributeChangeData& Data);
|
||||
void GiveDefaultAbilities();
|
||||
void ApplyDefaultAttributeEffect();
|
||||
void HandleDeath();
|
||||
void HandleRespawn();
|
||||
|
||||
UFUNCTION(NetMulticast, Reliable)
|
||||
void MulticastHandleDeath();
|
||||
|
||||
UFUNCTION(NetMulticast, Reliable)
|
||||
void MulticastRestoreRespawnState();
|
||||
|
||||
bool bHasGivenDefaultAbilities = false;
|
||||
bool bHasAppliedDefaultAttributeEffect = false;
|
||||
bool bHasHandledDeath = false;
|
||||
bool bHasNotifiedDeath = false;
|
||||
FDelegateHandle HealthChangedHandle;
|
||||
FTimerHandle RespawnTimer;
|
||||
};
|
||||
|
||||
@@ -18,6 +18,8 @@ public:
|
||||
UMainAttributeSet();
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
|
||||
virtual void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health)
|
||||
FGameplayAttributeData Health;
|
||||
|
||||
@@ -4,18 +4,30 @@
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "GameFramework/Controller.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "EnhancedInputSubsystems.h"
|
||||
#include "Engine/World.h"
|
||||
#include "InputActionValue.h"
|
||||
#include "MainAttributeSet.h"
|
||||
#include "MainPlayerState.h"
|
||||
#include "PvPDemo.h"
|
||||
#include "PvPDemoGameMode.h"
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "AttributeSet.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
FGameplayTag GetDeadTag()
|
||||
{
|
||||
return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
APvPDemoCharacter::APvPDemoCharacter()
|
||||
{
|
||||
@@ -71,6 +83,13 @@ void APvPDemoCharacter::OnRep_PlayerState()
|
||||
InitAbilityActorInfo();
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
UnbindHealthChangedDelegate();
|
||||
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
{
|
||||
// Set up action bindings
|
||||
@@ -173,11 +192,14 @@ void APvPDemoCharacter::InitAbilityActorInfo()
|
||||
{
|
||||
AMainPlayerState* MainPlayerState = GetPlayerState<AMainPlayerState>();
|
||||
check(MainPlayerState);
|
||||
|
||||
UnbindHealthChangedDelegate();
|
||||
|
||||
// 设置ASC的所有者,OwnerActor是所有者,AvatarActor是游戏中的形象
|
||||
MainPlayerState->GetAbilitySystemComponent()->InitAbilityActorInfo(MainPlayerState, this);
|
||||
AbilitySystemComponent = MainPlayerState->GetAbilitySystemComponent();
|
||||
AttributeSet = MainPlayerState->GetAttributeSet();
|
||||
BindHealthChangedDelegate();
|
||||
|
||||
if (HasAuthority() && AbilitySystemComponent && HeldItem)
|
||||
{
|
||||
@@ -187,6 +209,97 @@ void APvPDemoCharacter::InitAbilityActorInfo()
|
||||
}
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::BindHealthChangedDelegate()
|
||||
{
|
||||
if (!AbilitySystemComponent || HealthChangedHandle.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HealthChangedHandle = AbilitySystemComponent
|
||||
->GetGameplayAttributeValueChangeDelegate(UMainAttributeSet::GetHealthAttribute())
|
||||
.AddUObject(this, &ThisClass::OnHealthChanged);
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::UnbindHealthChangedDelegate()
|
||||
{
|
||||
if (!AbilitySystemComponent || !HealthChangedHandle.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AbilitySystemComponent
|
||||
->GetGameplayAttributeValueChangeDelegate(UMainAttributeSet::GetHealthAttribute())
|
||||
.Remove(HealthChangedHandle);
|
||||
HealthChangedHandle.Reset();
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::OnHealthChanged(const FOnAttributeChangeData& Data)
|
||||
{
|
||||
if (HasAuthority() && Data.NewValue <= 0.f)
|
||||
{
|
||||
HandleDeath();
|
||||
}
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::HandleDeath()
|
||||
{
|
||||
if (bHasHandledDeath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bHasHandledDeath = true;
|
||||
|
||||
if (AbilitySystemComponent)
|
||||
{
|
||||
AbilitySystemComponent->SetLooseGameplayTagCount(GetDeadTag(), 1, EGameplayTagReplicationState::TagOnly);
|
||||
}
|
||||
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
if (APvPDemoGameMode* GameMode = World->GetAuthGameMode<APvPDemoGameMode>())
|
||||
{
|
||||
GameMode->RequestPlayerRespawn(GetController(), this, RespawnDelay);
|
||||
}
|
||||
}
|
||||
|
||||
MulticastHandleDeath();
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::MulticastHandleDeath_Implementation()
|
||||
{
|
||||
if (bHasNotifiedDeath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bHasNotifiedDeath = true;
|
||||
|
||||
GetCharacterMovement()->DisableMovement();
|
||||
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
GetMesh()->SetHiddenInGame(true, true);
|
||||
|
||||
BP_OnDeath();
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::RestoreRespawnState()
|
||||
{
|
||||
if (!HasAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MulticastRestoreRespawnState();
|
||||
}
|
||||
|
||||
void APvPDemoCharacter::MulticastRestoreRespawnState_Implementation()
|
||||
{
|
||||
GetCharacterMovement()->SetMovementMode(MOVE_Walking);
|
||||
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
|
||||
GetMesh()->SetHiddenInGame(false, true);
|
||||
}
|
||||
|
||||
bool APvPDemoCharacter::AddHeldItemTag(FGameplayTag Tag)
|
||||
{
|
||||
if (!HasAuthority())
|
||||
|
||||
@@ -14,6 +14,7 @@ class UInputAction;
|
||||
class UAbilitySystemComponent;
|
||||
class UAttributeSet;
|
||||
struct FInputActionValue;
|
||||
struct FOnAttributeChangeData;
|
||||
class UGameplayAbility;
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);
|
||||
@@ -79,6 +80,7 @@ protected:
|
||||
|
||||
/** Initialize input action bindings */
|
||||
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -109,6 +111,10 @@ public:
|
||||
// UFUNCTION(BlueprintCallable, Category="Input")
|
||||
// virtual void DoAttack();
|
||||
|
||||
protected:
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Death")
|
||||
void BP_OnDeath();
|
||||
|
||||
public:
|
||||
|
||||
/** Returns CameraBoom subobject **/
|
||||
@@ -119,14 +125,33 @@ public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Items")
|
||||
TSubclassOf<UGameplayAbility> HeldItem;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Respawn", meta=(ClampMin="0", Units="s"))
|
||||
float RespawnDelay = 2.f;
|
||||
|
||||
void RestoreRespawnState();
|
||||
|
||||
private:
|
||||
void InitAbilityActorInfo();
|
||||
void BindHealthChangedDelegate();
|
||||
void UnbindHealthChangedDelegate();
|
||||
void OnHealthChanged(const FOnAttributeChangeData& Data);
|
||||
void HandleDeath();
|
||||
|
||||
UFUNCTION(NetMulticast, Reliable)
|
||||
void MulticastHandleDeath();
|
||||
|
||||
UFUNCTION(NetMulticast, Reliable)
|
||||
void MulticastRestoreRespawnState();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool AddHeldItemTag(FGameplayTag Tag);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool RemoveHeldItemTag(FGameplayTag Tag);
|
||||
|
||||
FDelegateHandle HealthChangedHandle;
|
||||
bool bHasHandledDeath = false;
|
||||
bool bHasNotifiedDeath = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,92 @@
|
||||
|
||||
#include "PvPDemoGameMode.h"
|
||||
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "GameFramework/Controller.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "MainAttributeSet.h"
|
||||
#include "MainPlayerState.h"
|
||||
#include "PvPDemoCharacter.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
FGameplayTag GetDeadTag()
|
||||
{
|
||||
return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead")));
|
||||
}
|
||||
}
|
||||
|
||||
APvPDemoGameMode::APvPDemoGameMode()
|
||||
{
|
||||
// stub
|
||||
}
|
||||
|
||||
void APvPDemoGameMode::RequestPlayerRespawn_Implementation(AController* Controller, APawn* DeadPawn, float DelaySeconds)
|
||||
{
|
||||
if (!Controller)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const TWeakObjectPtr<AController> ControllerWeak = Controller;
|
||||
const TWeakObjectPtr<APawn> DeadPawnWeak = DeadPawn;
|
||||
|
||||
FTimerDelegate RespawnDelegate;
|
||||
RespawnDelegate.BindWeakLambda(this, [this, ControllerWeak, DeadPawnWeak]()
|
||||
{
|
||||
RespawnPlayer(ControllerWeak.Get(), DeadPawnWeak.Get());
|
||||
});
|
||||
|
||||
FTimerHandle RespawnTimer;
|
||||
if (DelaySeconds <= 0.f)
|
||||
{
|
||||
RespawnDelegate.ExecuteIfBound();
|
||||
return;
|
||||
}
|
||||
|
||||
GetWorldTimerManager().SetTimer(RespawnTimer, RespawnDelegate, DelaySeconds, false);
|
||||
}
|
||||
|
||||
void APvPDemoGameMode::RespawnPlayer(AController* Controller, APawn* DeadPawn)
|
||||
{
|
||||
if (!Controller)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ResetRespawnAttributes(Controller);
|
||||
|
||||
APawn* OldPawn = DeadPawn;
|
||||
if (OldPawn && Controller->GetPawn() == OldPawn)
|
||||
{
|
||||
Controller->UnPossess();
|
||||
}
|
||||
|
||||
RestartPlayer(Controller);
|
||||
|
||||
if (APvPDemoCharacter* RespawnedCharacter = Cast<APvPDemoCharacter>(Controller->GetPawn()))
|
||||
{
|
||||
RespawnedCharacter->RestoreRespawnState();
|
||||
}
|
||||
|
||||
if (OldPawn && OldPawn != Controller->GetPawn() && Controller->GetPawn())
|
||||
{
|
||||
OldPawn->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void APvPDemoGameMode::ResetRespawnAttributes(AController* Controller) const
|
||||
{
|
||||
const AMainPlayerState* MainPlayerState = Controller ? Controller->GetPlayerState<AMainPlayerState>() : nullptr;
|
||||
UAbilitySystemComponent* ASC = MainPlayerState ? MainPlayerState->GetAbilitySystemComponent() : nullptr;
|
||||
if (!ASC)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ASC->SetLooseGameplayTagCount(GetDeadTag(), 0, EGameplayTagReplicationState::TagOnly);
|
||||
|
||||
const float MaxHealth = ASC->GetNumericAttribute(UMainAttributeSet::GetMaxHealthAttribute());
|
||||
ASC->SetNumericAttributeBase(UMainAttributeSet::GetHealthAttribute(), MaxHealth);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "GameFramework/GameModeBase.h"
|
||||
#include "PvPDemoGameMode.generated.h"
|
||||
|
||||
class AController;
|
||||
class APawn;
|
||||
|
||||
/**
|
||||
* Simple GameMode for a third person game
|
||||
*/
|
||||
@@ -18,7 +21,15 @@ public:
|
||||
|
||||
/** Constructor */
|
||||
APvPDemoGameMode();
|
||||
|
||||
UFUNCTION(BlueprintAuthorityOnly, BlueprintNativeEvent, Category="Respawn")
|
||||
void RequestPlayerRespawn(AController* Controller, APawn* DeadPawn, float DelaySeconds);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="Respawn")
|
||||
void RespawnPlayer(AController* Controller, APawn* DeadPawn);
|
||||
|
||||
private:
|
||||
void ResetRespawnAttributes(AController* Controller) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user