[박치영] Stat Component 작업 중
parent
5706b3a1bf
commit
312cf74de4
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -9,7 +9,8 @@
|
||||||
"Type": "Runtime",
|
"Type": "Runtime",
|
||||||
"LoadingPhase": "Default",
|
"LoadingPhase": "Default",
|
||||||
"AdditionalDependencies": [
|
"AdditionalDependencies": [
|
||||||
"Engine"
|
"Engine",
|
||||||
|
"UMG"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -20,13 +20,29 @@ ABaseWeapon::ABaseWeapon()
|
||||||
InputCollisionObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn));
|
InputCollisionObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn));
|
||||||
CollisionComponent->SetCollisionObjectTypes(InputCollisionObjectTypes);
|
CollisionComponent->SetCollisionObjectTypes(InputCollisionObjectTypes);
|
||||||
CollisionComponent->SetDrawDebugType(EDrawDebugTrace::None);
|
CollisionComponent->SetDrawDebugType(EDrawDebugTrace::None);
|
||||||
|
|
||||||
|
ActionStatCost.Add(ECharacterAction::LightAttack, 10.f);
|
||||||
|
ActionStatCost.Add(ECharacterAction::HeavyAttack, 15.f);
|
||||||
|
ActionStatCost.Add(ECharacterAction::ChargedAttack, 20.f);
|
||||||
|
ActionStatCost.Add(ECharacterAction::FallingAttack, 10.f);
|
||||||
|
ActionStatCost.Add(ECharacterAction::SprintAttack, 10.f);
|
||||||
|
ActionStatCost.Add(ECharacterAction::Dodge, 20.f);
|
||||||
|
|
||||||
|
ActionDamageMultiplier.Add(ECharacterAction::LightAttack, 1.f);
|
||||||
|
ActionDamageMultiplier.Add(ECharacterAction::HeavyAttack, 1.4f);
|
||||||
|
ActionDamageMultiplier.Add(ECharacterAction::ChargedAttack, 1.5f);
|
||||||
|
ActionDamageMultiplier.Add(ECharacterAction::FallingAttack, 1.2f);
|
||||||
|
ActionDamageMultiplier.Add(ECharacterAction::SprintAttack, 1.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABaseWeapon::OnEquipped()
|
void ABaseWeapon::OnEquipped()
|
||||||
{
|
{
|
||||||
SetIsEquipped(true);
|
SetIsEquipped(true);
|
||||||
AActor* owner = GetOwner();
|
AActor* owner = GetOwner();
|
||||||
|
if (!owner)
|
||||||
|
return;
|
||||||
CombatComponent = owner->GetComponentByClass<UCombatComponent>();
|
CombatComponent = owner->GetComponentByClass<UCombatComponent>();
|
||||||
|
OwnerStateManager = owner->GetComponentByClass<UStateManagerComponent>();
|
||||||
|
|
||||||
if (CombatComponent->GetCombatEnabled())
|
if (CombatComponent->GetCombatEnabled())
|
||||||
AttachActor(HandSocketName);
|
AttachActor(HandSocketName);
|
||||||
|
@ -62,6 +78,24 @@ void ABaseWeapon::SimulateWeaponPhysics()
|
||||||
GetItemMesh()->SetSimulatePhysics(true);
|
GetItemMesh()->SetSimulatePhysics(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float ABaseWeapon::GetStatCostForAction()
|
||||||
|
{
|
||||||
|
if (!IsValid(OwnerStateManager))
|
||||||
|
return 0.f;
|
||||||
|
|
||||||
|
return *ActionStatCost.Find(OwnerStateManager->GetCurrentAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
float ABaseWeapon::GetDamage()
|
||||||
|
{
|
||||||
|
if (!IsValid(OwnerStateManager))
|
||||||
|
return Damage;
|
||||||
|
float outDamage = *ActionDamageMultiplier.Find(OwnerStateManager->GetCurrentAction());
|
||||||
|
outDamage = FMath::Clamp(outDamage, 1.f, outDamage) * Damage;
|
||||||
|
|
||||||
|
return outDamage;
|
||||||
|
}
|
||||||
|
|
||||||
TArray<UAnimMontage*> ABaseWeapon::GetActionMontage(ECharacterAction characterAction)
|
TArray<UAnimMontage*> ABaseWeapon::GetActionMontage(ECharacterAction characterAction)
|
||||||
{
|
{
|
||||||
TArray<UAnimMontage*> outputArr;
|
TArray<UAnimMontage*> outputArr;
|
||||||
|
|
|
@ -32,6 +32,8 @@ public:
|
||||||
public:
|
public:
|
||||||
//Normal
|
//Normal
|
||||||
void SimulateWeaponPhysics();
|
void SimulateWeaponPhysics();
|
||||||
|
float GetStatCostForAction();
|
||||||
|
float GetDamage();
|
||||||
public:
|
public:
|
||||||
TArray<UAnimMontage*> GetActionMontage(ECharacterAction characterAction);
|
TArray<UAnimMontage*> GetActionMontage(ECharacterAction characterAction);
|
||||||
|
|
||||||
|
@ -45,6 +47,8 @@ protected:
|
||||||
TObjectPtr<class UCombatComponent> CombatComponent;
|
TObjectPtr<class UCombatComponent> CombatComponent;
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components")
|
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components")
|
||||||
TObjectPtr<class UCollisionComponent> CollisionComponent;
|
TObjectPtr<class UCollisionComponent> CollisionComponent;
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components")
|
||||||
|
TObjectPtr<UStateManagerComponent> OwnerStateManager;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Montages")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Montages")
|
||||||
TObjectPtr<UAnimMontage> EnterCombat;
|
TObjectPtr<UAnimMontage> EnterCombat;
|
||||||
|
@ -65,4 +69,9 @@ protected:
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
|
||||||
float Damage;
|
float Damage;
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
|
||||||
|
TMap<ECharacterAction, float> ActionStatCost;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
|
||||||
|
TMap<ECharacterAction, float> ActionDamageMultiplier;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "Interface/Interact.h"
|
#include "Interface/Interact.h"
|
||||||
#include "Actor/BaseWeapon.h"
|
#include "Actor/BaseWeapon.h"
|
||||||
#include "Components/CombatComponent.h"
|
#include "Components/CombatComponent.h"
|
||||||
|
#include "Components/StatsComponent.h"
|
||||||
#include "Engine/DamageEvents.h"
|
#include "Engine/DamageEvents.h"
|
||||||
#include "Kismet/KismetSystemLibrary.h"
|
#include "Kismet/KismetSystemLibrary.h"
|
||||||
#include "Kismet/KismetMathLibrary.h"
|
#include "Kismet/KismetMathLibrary.h"
|
||||||
|
@ -71,6 +72,10 @@ ACombatCharacter::ACombatCharacter()
|
||||||
StateManagerComponent->OnActionBegin.AddUObject(this, &ACombatCharacter::CharacterActionBegin);
|
StateManagerComponent->OnActionBegin.AddUObject(this, &ACombatCharacter::CharacterActionBegin);
|
||||||
StateManagerComponent->OnActionEnd.AddUObject(this, &ACombatCharacter::CharacterActionEnd);
|
StateManagerComponent->OnActionEnd.AddUObject(this, &ACombatCharacter::CharacterActionEnd);
|
||||||
|
|
||||||
|
// Setting StatsComponent
|
||||||
|
StatsComponent = CreateDefaultSubobject<UStatsComponent>(TEXT("StatsComponent"));
|
||||||
|
StatsComponent->OnCurrentStatValueUpdated.AddUObject(this, &ACombatCharacter::CharacterCurrentStatValueUpdated);
|
||||||
|
|
||||||
//Setting MovementSpeed
|
//Setting MovementSpeed
|
||||||
MovementSpeedMode = EMovementSpeedMode::Jogging;
|
MovementSpeedMode = EMovementSpeedMode::Jogging;
|
||||||
WalkingSpeed = 200.f;
|
WalkingSpeed = 200.f;
|
||||||
|
@ -103,6 +108,8 @@ void ACombatCharacter::BeginPlay()
|
||||||
ABaseEquippable* SpawnItem = Cast<ABaseEquippable>(GetWorld()->SpawnActor(Weapon, &GetActorTransform(), spawnParam));
|
ABaseEquippable* SpawnItem = Cast<ABaseEquippable>(GetWorld()->SpawnActor(Weapon, &GetActorTransform(), spawnParam));
|
||||||
if (SpawnItem)
|
if (SpawnItem)
|
||||||
SpawnItem->OnEquipped();
|
SpawnItem->OnEquipped();
|
||||||
|
|
||||||
|
StatsComponent->InitializeStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
float ACombatCharacter::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
|
float ACombatCharacter::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
|
||||||
|
@ -113,7 +120,7 @@ float ACombatCharacter::TakeDamage(float Damage, FDamageEvent const& DamageEvent
|
||||||
{
|
{
|
||||||
const FPointDamageEvent* PointDamageEvent = static_cast<const FPointDamageEvent*>(&DamageEvent);
|
const FPointDamageEvent* PointDamageEvent = static_cast<const FPointDamageEvent*>(&DamageEvent);
|
||||||
|
|
||||||
CharacterTakeDamage(fDamage);
|
StatsComponent->TakeDamageOnStat(Damage);
|
||||||
|
|
||||||
//Play Sound
|
//Play Sound
|
||||||
UGameplayStatics::PlaySoundAtLocation(this, HitSound, PointDamageEvent->HitInfo.Location);
|
UGameplayStatics::PlaySoundAtLocation(this, HitSound, PointDamageEvent->HitInfo.Location);
|
||||||
|
@ -200,7 +207,6 @@ void ACombatCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerIn
|
||||||
EnhancedInputComponent->BindAction(LightAttackAction, ETriggerEvent::Triggered, this, &ACombatCharacter::LightChargeAttack);
|
EnhancedInputComponent->BindAction(LightAttackAction, ETriggerEvent::Triggered, this, &ACombatCharacter::LightChargeAttack);
|
||||||
EnhancedInputComponent->BindAction(LightAttackAction, ETriggerEvent::Completed, this, &ACombatCharacter::LightAttack);
|
EnhancedInputComponent->BindAction(LightAttackAction, ETriggerEvent::Completed, this, &ACombatCharacter::LightAttack);
|
||||||
|
|
||||||
|
|
||||||
//HeavyAttack
|
//HeavyAttack
|
||||||
EnhancedInputComponent->BindAction(HeavyAttackAction, ETriggerEvent::Started, this, &ACombatCharacter::HeavyAttack);
|
EnhancedInputComponent->BindAction(HeavyAttackAction, ETriggerEvent::Started, this, &ACombatCharacter::HeavyAttack);
|
||||||
|
|
||||||
|
@ -308,7 +314,15 @@ void ACombatCharacter::LightChargeAttack(const FInputActionInstance& Instance)
|
||||||
if (bAttackCharged)
|
if (bAttackCharged)
|
||||||
{
|
{
|
||||||
if (CanPerformAttack())
|
if (CanPerformAttack())
|
||||||
|
{
|
||||||
PerformAttack(ECharacterAction::ChargedAttack, CombatComponent->GetAttackCount());
|
PerformAttack(ECharacterAction::ChargedAttack, CombatComponent->GetAttackCount());
|
||||||
|
ABaseWeapon* pBaseWeapon = CombatComponent->GetMainWeapon();
|
||||||
|
if (IsValid(pBaseWeapon))
|
||||||
|
{
|
||||||
|
StatsComponent->ModifyCurrentStatValue(EStats::Stamina, -1.f * pBaseWeapon->GetStatCostForAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +340,15 @@ void ACombatCharacter::HeavyAttack(const FInputActionValue& Value)
|
||||||
void ACombatCharacter::Dodge(const FInputActionValue& Value)
|
void ACombatCharacter::Dodge(const FInputActionValue& Value)
|
||||||
{
|
{
|
||||||
if (CanPerformDodge())
|
if (CanPerformDodge())
|
||||||
|
{
|
||||||
PerformDodge();
|
PerformDodge();
|
||||||
|
ABaseWeapon* pBaseWeapon = CombatComponent->GetMainWeapon();
|
||||||
|
if (IsValid(pBaseWeapon))
|
||||||
|
{
|
||||||
|
StatsComponent->ModifyCurrentStatValue(EStats::Stamina, -1.f * pBaseWeapon->GetStatCostForAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACombatCharacter::ToggleWalk(const FInputActionValue& Value)
|
void ACombatCharacter::ToggleWalk(const FInputActionValue& Value)
|
||||||
|
@ -340,13 +362,18 @@ void ACombatCharacter::ToggleWalk(const FInputActionValue& Value)
|
||||||
|
|
||||||
void ACombatCharacter::StartSprint(const FInputActionValue& Value)
|
void ACombatCharacter::StartSprint(const FInputActionValue& Value)
|
||||||
{
|
{
|
||||||
SetMovementSpeedMode(EMovementSpeedMode::Sprinting);
|
if (CanPerformSprint())
|
||||||
|
{
|
||||||
|
SetMovementSpeedMode(EMovementSpeedMode::Sprinting);
|
||||||
|
UWorld* World = GEngine->GetWorldFromContextObjectChecked(this);
|
||||||
|
if (World)
|
||||||
|
World->GetTimerManager().SetTimer(StaminaTimerHandle, this, &ACombatCharacter::SprintStaminaCost, 0.1f, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACombatCharacter::StopSprint(const FInputActionValue& Value)
|
void ACombatCharacter::StopSprint(const FInputActionValue& Value)
|
||||||
{
|
{
|
||||||
if (GetMovementSpeedMode() == EMovementSpeedMode::Sprinting)
|
DisableSprint();
|
||||||
SetMovementSpeedMode(EMovementSpeedMode::Jogging);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACombatCharacter::CharacterStateBegin(ECharacterState CharState)
|
void ACombatCharacter::CharacterStateBegin(ECharacterState CharState)
|
||||||
|
@ -450,6 +477,14 @@ void ACombatCharacter::CharacterActionEnd(ECharacterAction CharAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ACombatCharacter::CharacterCurrentStatValueUpdated(EStats statType, float value)
|
||||||
|
{
|
||||||
|
if (!(statType == EStats::Health) || value > 0.f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
StateManagerComponent->SetCurrentState(ECharacterState::Dead);
|
||||||
|
}
|
||||||
|
|
||||||
void ACombatCharacter::ToggleCombatEvent()
|
void ACombatCharacter::ToggleCombatEvent()
|
||||||
{
|
{
|
||||||
ABaseWeapon* baseWeapon = CombatComponent->GetMainWeapon();
|
ABaseWeapon* baseWeapon = CombatComponent->GetMainWeapon();
|
||||||
|
@ -471,20 +506,15 @@ void ACombatCharacter::AttackEvent()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (CombatComponent->GetCombatEnabled())
|
if (CombatComponent->GetCombatEnabled())
|
||||||
|
{
|
||||||
PerformAttack(GetDesiredAttackType(), CombatComponent->GetAttackCount());
|
PerformAttack(GetDesiredAttackType(), CombatComponent->GetAttackCount());
|
||||||
|
if (IsValid(CombatComponent->GetMainWeapon()))
|
||||||
|
StatsComponent->ModifyCurrentStatValue(EStats::Stamina, -1.f * CombatComponent->GetMainWeapon()->GetStatCostForAction());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ToggleCombatEvent();
|
ToggleCombatEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACombatCharacter::CharacterTakeDamage(float InDamage)
|
|
||||||
{
|
|
||||||
float tmp = Health - InDamage;
|
|
||||||
Health = UKismetMathLibrary::Clamp(tmp, 0, Health);
|
|
||||||
|
|
||||||
if (Health <= 0)
|
|
||||||
StateManagerComponent->SetCurrentState(ECharacterState::Dead);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ACombatCharacter::ApplyHitReactionPhysicsVelocity(float InitialSpeed)
|
void ACombatCharacter::ApplyHitReactionPhysicsVelocity(float InitialSpeed)
|
||||||
{
|
{
|
||||||
if (!GetMesh())
|
if (!GetMesh())
|
||||||
|
@ -540,6 +570,32 @@ bool ACombatCharacter::ResetChargeAttack()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ACombatCharacter::DisableSprint()
|
||||||
|
{
|
||||||
|
UWorld* World = GEngine->GetWorldFromContextObjectChecked(this);
|
||||||
|
if (World)
|
||||||
|
World->GetTimerManager().ClearTimer(StaminaTimerHandle);
|
||||||
|
|
||||||
|
if (GetMovementSpeedMode() == EMovementSpeedMode::Sprinting)
|
||||||
|
SetMovementSpeedMode(EMovementSpeedMode::Jogging);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ACombatCharacter::SprintStaminaCost()
|
||||||
|
{
|
||||||
|
if (!CanPerformSprint())
|
||||||
|
{
|
||||||
|
DisableSprint();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsComponent->ModifyCurrentStatValue(EStats::Stamina, -2.f);
|
||||||
|
if (StatsComponent->GetCurrentStatValue(EStats::Stamina) < 10.f)
|
||||||
|
{
|
||||||
|
DisableSprint();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ACombatCharacter::PerformAttack(ECharacterAction attackType, int32 attackIndex)
|
void ACombatCharacter::PerformAttack(ECharacterAction attackType, int32 attackIndex)
|
||||||
{
|
{
|
||||||
ABaseWeapon* CurrentWeapon = CombatComponent->GetMainWeapon();
|
ABaseWeapon* CurrentWeapon = CombatComponent->GetMainWeapon();
|
||||||
|
@ -677,6 +733,8 @@ bool ACombatCharacter::CanPerformAttack()
|
||||||
ECharacterState::GeneralActionState
|
ECharacterState::GeneralActionState
|
||||||
};
|
};
|
||||||
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
|
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
|
||||||
|
ReturnValue &= (StatsComponent->GetCurrentStatValue(EStats::Stamina) >= 10.f);
|
||||||
|
|
||||||
return ReturnValue;
|
return ReturnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,6 +749,7 @@ bool ACombatCharacter::CanPerformDodge()
|
||||||
};
|
};
|
||||||
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
|
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
|
||||||
ReturnValue &= !GetCharacterMovement()->IsFalling();
|
ReturnValue &= !GetCharacterMovement()->IsFalling();
|
||||||
|
ReturnValue &= (StatsComponent->GetCurrentStatValue(EStats::Stamina) >= 10.f);
|
||||||
return ReturnValue;
|
return ReturnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,6 +777,11 @@ bool ACombatCharacter::CanReceiveHitReaction()
|
||||||
return ReturnValue;
|
return ReturnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ACombatCharacter::CanPerformSprint()
|
||||||
|
{
|
||||||
|
return (FMath::IsNearlyEqual(GetVelocity().Length(), 0.f)) == false;
|
||||||
|
}
|
||||||
|
|
||||||
ECharacterAction ACombatCharacter::GetDesiredAttackType()
|
ECharacterAction ACombatCharacter::GetDesiredAttackType()
|
||||||
{
|
{
|
||||||
if (GetCharacterMovement()->IsFalling())
|
if (GetCharacterMovement()->IsFalling())
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "InputAction.h"
|
#include "InputAction.h"
|
||||||
#include "Interface/CombatInterface.h"
|
#include "Interface/CombatInterface.h"
|
||||||
#include "Components/StateManagerComponent.h"
|
#include "Components/StateManagerComponent.h"
|
||||||
|
#include "Components/StatsComponent.h"
|
||||||
#include "Definitions/GameEnums.h"
|
#include "Definitions/GameEnums.h"
|
||||||
#include "CombatCharacter.generated.h"
|
#include "CombatCharacter.generated.h"
|
||||||
|
|
||||||
|
@ -119,16 +120,18 @@ private://Delegate
|
||||||
void CharacterStateEnd(ECharacterState CharState);
|
void CharacterStateEnd(ECharacterState CharState);
|
||||||
void CharacterActionBegin(ECharacterAction CharAction);
|
void CharacterActionBegin(ECharacterAction CharAction);
|
||||||
void CharacterActionEnd(ECharacterAction CharAction);
|
void CharacterActionEnd(ECharacterAction CharAction);
|
||||||
|
void CharacterCurrentStatValueUpdated(EStats statType, float value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ToggleCombatEvent();
|
void ToggleCombatEvent();
|
||||||
void AttackEvent();
|
void AttackEvent();
|
||||||
void CharacterTakeDamage(float InDamage);
|
|
||||||
void ApplyHitReactionPhysicsVelocity(float InitialSpeed);
|
void ApplyHitReactionPhysicsVelocity(float InitialSpeed);
|
||||||
void EnableRagdoll();
|
void EnableRagdoll();
|
||||||
void SetMovementSpeedMode(EMovementSpeedMode NewSpeedMode);
|
void SetMovementSpeedMode(EMovementSpeedMode NewSpeedMode);
|
||||||
FORCEINLINE EMovementSpeedMode GetMovementSpeedMode() const { return MovementSpeedMode; }
|
FORCEINLINE EMovementSpeedMode GetMovementSpeedMode() const { return MovementSpeedMode; }
|
||||||
bool ResetChargeAttack();
|
bool ResetChargeAttack();
|
||||||
|
void DisableSprint();
|
||||||
|
void SprintStaminaCost();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PerformAttack(ECharacterAction attackType, int32 attackIndex);
|
void PerformAttack(ECharacterAction attackType, int32 attackIndex);
|
||||||
|
@ -142,13 +145,17 @@ private:
|
||||||
bool CanPerformDodge();
|
bool CanPerformDodge();
|
||||||
bool CanJumping();
|
bool CanJumping();
|
||||||
bool CanReceiveHitReaction();
|
bool CanReceiveHitReaction();
|
||||||
|
bool CanPerformSprint();
|
||||||
ECharacterAction GetDesiredAttackType();
|
ECharacterAction GetDesiredAttackType();
|
||||||
public:
|
public:
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
|
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
|
||||||
TObjectPtr<class UCombatComponent> CombatComponent;
|
TObjectPtr<class UCombatComponent> CombatComponent;
|
||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
|
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
|
||||||
TObjectPtr<class UStateManagerComponent> StateManagerComponent;
|
TObjectPtr<UStateManagerComponent> StateManagerComponent;
|
||||||
|
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
|
||||||
|
TObjectPtr<UStatsComponent> StatsComponent;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta = (AllowPrivateAccess = "true"))
|
||||||
TSubclassOf<class ABaseEquippable> Weapon;
|
TSubclassOf<class ABaseEquippable> Weapon;
|
||||||
|
@ -180,6 +187,9 @@ public:
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats", meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats", meta = (AllowPrivateAccess = "true"))
|
||||||
float Health;
|
float Health;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FTimerHandle StaminaTimerHandle;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsHeavyAttack;
|
bool IsHeavyAttack;
|
||||||
float AttackHeldTime;
|
float AttackHeldTime;
|
||||||
|
|
|
@ -13,6 +13,7 @@ UStatsComponent::UStatsComponent()
|
||||||
PrimaryComponentTick.bCanEverTick = true;
|
PrimaryComponentTick.bCanEverTick = true;
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
StaminaRegenRate = 2.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,9 +71,9 @@ void UStatsComponent::TakeDamageOnStat(float inDamage)
|
||||||
float armor = GetCurrentStatValue(EStats::Armor);
|
float armor = GetCurrentStatValue(EStats::Armor);
|
||||||
calDamage = (inDamage / (inDamage + armor)) * inDamage;
|
calDamage = (inDamage / (inDamage + armor)) * inDamage;
|
||||||
calDamage = FMath::Clamp(calDamage, 0.f, calDamage);
|
calDamage = FMath::Clamp(calDamage, 0.f, calDamage);
|
||||||
ModifyCurrentStatValue(EStats::Health, -calDamage);
|
ModifyCurrentStatValue(EStats::Health, -calDamage, false);
|
||||||
|
|
||||||
FString debugStr = FString::Printf(TEXT("Damage : %d"), calDamage);
|
FString debugStr = FString::Printf(TEXT("Damage : %f"), calDamage);
|
||||||
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, debugStr);
|
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, debugStr);
|
||||||
|
|
||||||
if (GetCurrentStatValue(EStats::Health) <= 0.f)
|
if (GetCurrentStatValue(EStats::Health) <= 0.f)
|
||||||
|
@ -109,12 +110,20 @@ void UStatsComponent::StartRegen(EStats statType)
|
||||||
|
|
||||||
void UStatsComponent::RegenerateStamina()
|
void UStatsComponent::RegenerateStamina()
|
||||||
{
|
{
|
||||||
//TODO : 여기부터 시작
|
float curStamina = StaminaRegenRate + GetCurrentStatValue(EStats::Stamina);
|
||||||
|
curStamina = FMath::Clamp(curStamina, 0.f, GetMaxStatValue(EStats::Stamina));
|
||||||
|
SetCurrentStatValue(EStats::Stamina, curStamina);
|
||||||
|
|
||||||
|
if (GetCurrentStatValue(EStats::Stamina) >= GetMaxStatValue(EStats::Stamina))
|
||||||
|
{
|
||||||
|
UWorld* World = GEngine->GetWorldFromContextObjectChecked(this);
|
||||||
|
if (World)
|
||||||
|
World->GetTimerManager().ClearTimer(RegenTimerHandle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float UStatsComponent::GetBaseStatValue(EStats stat)
|
float UStatsComponent::GetBaseStatValue(EStats stat)
|
||||||
{
|
{
|
||||||
|
|
||||||
return BaseStats.Find(stat)->BaseValue;
|
return BaseStats.Find(stat)->BaseValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,10 @@ struct FBaseStat
|
||||||
|
|
||||||
FBaseStat() : BaseValue(0.f), MaxValue(0.f) {}
|
FBaseStat() : BaseValue(0.f), MaxValue(0.f) {}
|
||||||
FBaseStat(float InputBaseValue, float InputMaxValue) : BaseValue(InputBaseValue), MaxValue(InputMaxValue) {}
|
FBaseStat(float InputBaseValue, float InputMaxValue) : BaseValue(InputBaseValue), MaxValue(InputMaxValue) {}
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStat, meta = (AllowPrivateAccess = "true"))
|
||||||
float BaseValue;
|
float BaseValue;
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStat, meta = (AllowPrivateAccess = "true"))
|
||||||
float MaxValue;
|
float MaxValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,14 +67,15 @@ public:
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStats, meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStats, meta = (AllowPrivateAccess = "true"))
|
||||||
TMap<EStats, FBaseStat> BaseStats;
|
TMap<EStats, FBaseStat> BaseStats;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats, meta = (AllowPrivateAccess = "true"))
|
|
||||||
TMap<EStats, float> CurrentStats;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = StatRegen, meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = StatRegen, meta = (AllowPrivateAccess = "true"))
|
||||||
float StaminaRegenRate;
|
float StaminaRegenRate;
|
||||||
|
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Stats, meta = (AllowPrivateAccess = "true"))
|
||||||
|
TMap<EStats, float> CurrentStats;
|
||||||
|
|
||||||
|
public: //Delegate
|
||||||
|
FOnCurrentStatValueUpdated OnCurrentStatValueUpdated;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FTimerHandle RegenTimerHandle;
|
FTimerHandle RegenTimerHandle;
|
||||||
private:
|
|
||||||
FOnCurrentStatValueUpdated OnCurrentStatValueUpdated;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
|
||||||
|
#include "UI/UI_StatBar.h"
|
||||||
|
#include "Components/ProgressBar.h"
|
||||||
|
|
||||||
|
void UUI_StatBar::PreConstruct()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Blueprint/UserWidget.h"
|
||||||
|
#include "UI_StatBar.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class D1_API UUI_StatBar : public UUserWidget
|
||||||
|
{
|
||||||
|
|
||||||
|
GENERATED_BODY()
|
||||||
|
protected:
|
||||||
|
virtual void PreConstruct() override;
|
||||||
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, meta = (BindWidget))
|
||||||
|
class UProgressBar* StatBar;
|
||||||
|
};
|
Loading…
Reference in New Issue