[박치영] Stat Component 작업 중
parent
5706b3a1bf
commit
312cf74de4
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -9,7 +9,8 @@
|
|||
"Type": "Runtime",
|
||||
"LoadingPhase": "Default",
|
||||
"AdditionalDependencies": [
|
||||
"Engine"
|
||||
"Engine",
|
||||
"UMG"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -20,13 +20,29 @@ ABaseWeapon::ABaseWeapon()
|
|||
InputCollisionObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn));
|
||||
CollisionComponent->SetCollisionObjectTypes(InputCollisionObjectTypes);
|
||||
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()
|
||||
{
|
||||
SetIsEquipped(true);
|
||||
AActor* owner = GetOwner();
|
||||
if (!owner)
|
||||
return;
|
||||
CombatComponent = owner->GetComponentByClass<UCombatComponent>();
|
||||
OwnerStateManager = owner->GetComponentByClass<UStateManagerComponent>();
|
||||
|
||||
if (CombatComponent->GetCombatEnabled())
|
||||
AttachActor(HandSocketName);
|
||||
|
@ -62,6 +78,24 @@ void ABaseWeapon::SimulateWeaponPhysics()
|
|||
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*> outputArr;
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
public:
|
||||
//Normal
|
||||
void SimulateWeaponPhysics();
|
||||
float GetStatCostForAction();
|
||||
float GetDamage();
|
||||
public:
|
||||
TArray<UAnimMontage*> GetActionMontage(ECharacterAction characterAction);
|
||||
|
||||
|
@ -45,6 +47,8 @@ protected:
|
|||
TObjectPtr<class UCombatComponent> CombatComponent;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components")
|
||||
TObjectPtr<class UCollisionComponent> CollisionComponent;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components")
|
||||
TObjectPtr<UStateManagerComponent> OwnerStateManager;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Montages")
|
||||
TObjectPtr<UAnimMontage> EnterCombat;
|
||||
|
@ -65,4 +69,9 @@ protected:
|
|||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
|
||||
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 "Actor/BaseWeapon.h"
|
||||
#include "Components/CombatComponent.h"
|
||||
#include "Components/StatsComponent.h"
|
||||
#include "Engine/DamageEvents.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
#include "Kismet/KismetMathLibrary.h"
|
||||
|
@ -71,6 +72,10 @@ ACombatCharacter::ACombatCharacter()
|
|||
StateManagerComponent->OnActionBegin.AddUObject(this, &ACombatCharacter::CharacterActionBegin);
|
||||
StateManagerComponent->OnActionEnd.AddUObject(this, &ACombatCharacter::CharacterActionEnd);
|
||||
|
||||
// Setting StatsComponent
|
||||
StatsComponent = CreateDefaultSubobject<UStatsComponent>(TEXT("StatsComponent"));
|
||||
StatsComponent->OnCurrentStatValueUpdated.AddUObject(this, &ACombatCharacter::CharacterCurrentStatValueUpdated);
|
||||
|
||||
//Setting MovementSpeed
|
||||
MovementSpeedMode = EMovementSpeedMode::Jogging;
|
||||
WalkingSpeed = 200.f;
|
||||
|
@ -103,6 +108,8 @@ void ACombatCharacter::BeginPlay()
|
|||
ABaseEquippable* SpawnItem = Cast<ABaseEquippable>(GetWorld()->SpawnActor(Weapon, &GetActorTransform(), spawnParam));
|
||||
if (SpawnItem)
|
||||
SpawnItem->OnEquipped();
|
||||
|
||||
StatsComponent->InitializeStats();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
CharacterTakeDamage(fDamage);
|
||||
StatsComponent->TakeDamageOnStat(Damage);
|
||||
|
||||
//Play Sound
|
||||
UGameplayStatics::PlaySoundAtLocation(this, HitSound, PointDamageEvent->HitInfo.Location);
|
||||
|
@ -199,7 +206,6 @@ void ACombatCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerIn
|
|||
//LightAttack
|
||||
EnhancedInputComponent->BindAction(LightAttackAction, ETriggerEvent::Triggered, this, &ACombatCharacter::LightChargeAttack);
|
||||
EnhancedInputComponent->BindAction(LightAttackAction, ETriggerEvent::Completed, this, &ACombatCharacter::LightAttack);
|
||||
|
||||
|
||||
//HeavyAttack
|
||||
EnhancedInputComponent->BindAction(HeavyAttackAction, ETriggerEvent::Started, this, &ACombatCharacter::HeavyAttack);
|
||||
|
@ -308,7 +314,15 @@ void ACombatCharacter::LightChargeAttack(const FInputActionInstance& Instance)
|
|||
if (bAttackCharged)
|
||||
{
|
||||
if (CanPerformAttack())
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (CanPerformDodge())
|
||||
{
|
||||
PerformDodge();
|
||||
ABaseWeapon* pBaseWeapon = CombatComponent->GetMainWeapon();
|
||||
if (IsValid(pBaseWeapon))
|
||||
{
|
||||
StatsComponent->ModifyCurrentStatValue(EStats::Stamina, -1.f * pBaseWeapon->GetStatCostForAction());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ACombatCharacter::ToggleWalk(const FInputActionValue& Value)
|
||||
|
@ -340,13 +362,18 @@ void ACombatCharacter::ToggleWalk(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)
|
||||
{
|
||||
if (GetMovementSpeedMode() == EMovementSpeedMode::Sprinting)
|
||||
SetMovementSpeedMode(EMovementSpeedMode::Jogging);
|
||||
DisableSprint();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
ABaseWeapon* baseWeapon = CombatComponent->GetMainWeapon();
|
||||
|
@ -471,20 +506,15 @@ void ACombatCharacter::AttackEvent()
|
|||
return;
|
||||
|
||||
if (CombatComponent->GetCombatEnabled())
|
||||
{
|
||||
PerformAttack(GetDesiredAttackType(), CombatComponent->GetAttackCount());
|
||||
if (IsValid(CombatComponent->GetMainWeapon()))
|
||||
StatsComponent->ModifyCurrentStatValue(EStats::Stamina, -1.f * CombatComponent->GetMainWeapon()->GetStatCostForAction());
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
if (!GetMesh())
|
||||
|
@ -540,6 +570,32 @@ bool ACombatCharacter::ResetChargeAttack()
|
|||
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)
|
||||
{
|
||||
ABaseWeapon* CurrentWeapon = CombatComponent->GetMainWeapon();
|
||||
|
@ -677,6 +733,8 @@ bool ACombatCharacter::CanPerformAttack()
|
|||
ECharacterState::GeneralActionState
|
||||
};
|
||||
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
|
||||
ReturnValue &= (StatsComponent->GetCurrentStatValue(EStats::Stamina) >= 10.f);
|
||||
|
||||
return ReturnValue;
|
||||
}
|
||||
|
||||
|
@ -691,6 +749,7 @@ bool ACombatCharacter::CanPerformDodge()
|
|||
};
|
||||
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
|
||||
ReturnValue &= !GetCharacterMovement()->IsFalling();
|
||||
ReturnValue &= (StatsComponent->GetCurrentStatValue(EStats::Stamina) >= 10.f);
|
||||
return ReturnValue;
|
||||
}
|
||||
|
||||
|
@ -718,6 +777,11 @@ bool ACombatCharacter::CanReceiveHitReaction()
|
|||
return ReturnValue;
|
||||
}
|
||||
|
||||
bool ACombatCharacter::CanPerformSprint()
|
||||
{
|
||||
return (FMath::IsNearlyEqual(GetVelocity().Length(), 0.f)) == false;
|
||||
}
|
||||
|
||||
ECharacterAction ACombatCharacter::GetDesiredAttackType()
|
||||
{
|
||||
if (GetCharacterMovement()->IsFalling())
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "InputAction.h"
|
||||
#include "Interface/CombatInterface.h"
|
||||
#include "Components/StateManagerComponent.h"
|
||||
#include "Components/StatsComponent.h"
|
||||
#include "Definitions/GameEnums.h"
|
||||
#include "CombatCharacter.generated.h"
|
||||
|
||||
|
@ -119,16 +120,18 @@ private://Delegate
|
|||
void CharacterStateEnd(ECharacterState CharState);
|
||||
void CharacterActionBegin(ECharacterAction CharAction);
|
||||
void CharacterActionEnd(ECharacterAction CharAction);
|
||||
void CharacterCurrentStatValueUpdated(EStats statType, float value);
|
||||
|
||||
private:
|
||||
void ToggleCombatEvent();
|
||||
void AttackEvent();
|
||||
void CharacterTakeDamage(float InDamage);
|
||||
void ApplyHitReactionPhysicsVelocity(float InitialSpeed);
|
||||
void EnableRagdoll();
|
||||
void SetMovementSpeedMode(EMovementSpeedMode NewSpeedMode);
|
||||
FORCEINLINE EMovementSpeedMode GetMovementSpeedMode() const { return MovementSpeedMode; }
|
||||
bool ResetChargeAttack();
|
||||
void DisableSprint();
|
||||
void SprintStaminaCost();
|
||||
|
||||
private:
|
||||
void PerformAttack(ECharacterAction attackType, int32 attackIndex);
|
||||
|
@ -142,13 +145,17 @@ private:
|
|||
bool CanPerformDodge();
|
||||
bool CanJumping();
|
||||
bool CanReceiveHitReaction();
|
||||
bool CanPerformSprint();
|
||||
ECharacterAction GetDesiredAttackType();
|
||||
public:
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
|
||||
TObjectPtr<class UCombatComponent> CombatComponent;
|
||||
|
||||
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"))
|
||||
TSubclassOf<class ABaseEquippable> Weapon;
|
||||
|
@ -180,6 +187,9 @@ public:
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats", meta = (AllowPrivateAccess = "true"))
|
||||
float Health;
|
||||
|
||||
private:
|
||||
FTimerHandle StaminaTimerHandle;
|
||||
|
||||
private:
|
||||
bool IsHeavyAttack;
|
||||
float AttackHeldTime;
|
||||
|
|
|
@ -13,6 +13,7 @@ UStatsComponent::UStatsComponent()
|
|||
PrimaryComponentTick.bCanEverTick = true;
|
||||
|
||||
// ...
|
||||
StaminaRegenRate = 2.f;
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,9 +71,9 @@ void UStatsComponent::TakeDamageOnStat(float inDamage)
|
|||
float armor = GetCurrentStatValue(EStats::Armor);
|
||||
calDamage = (inDamage / (inDamage + armor)) * inDamage;
|
||||
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);
|
||||
|
||||
if (GetCurrentStatValue(EStats::Health) <= 0.f)
|
||||
|
@ -109,12 +110,20 @@ void UStatsComponent::StartRegen(EStats statType)
|
|||
|
||||
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)
|
||||
{
|
||||
|
||||
return BaseStats.Find(stat)->BaseValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,10 @@ struct FBaseStat
|
|||
|
||||
FBaseStat() : BaseValue(0.f), MaxValue(0.f) {}
|
||||
FBaseStat(float InputBaseValue, float InputMaxValue) : BaseValue(InputBaseValue), MaxValue(InputMaxValue) {}
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStat, meta = (AllowPrivateAccess = "true"))
|
||||
float BaseValue;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStat, meta = (AllowPrivateAccess = "true"))
|
||||
float MaxValue;
|
||||
};
|
||||
|
||||
|
@ -64,14 +67,15 @@ public:
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStats, meta = (AllowPrivateAccess = "true"))
|
||||
TMap<EStats, FBaseStat> BaseStats;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats, meta = (AllowPrivateAccess = "true"))
|
||||
TMap<EStats, float> CurrentStats;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = StatRegen, meta = (AllowPrivateAccess = "true"))
|
||||
float StaminaRegenRate;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Stats, meta = (AllowPrivateAccess = "true"))
|
||||
TMap<EStats, float> CurrentStats;
|
||||
|
||||
public: //Delegate
|
||||
FOnCurrentStatValueUpdated OnCurrentStatValueUpdated;
|
||||
|
||||
private:
|
||||
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