diff --git a/Source/D1/Components/StatsComponent.cpp b/Source/D1/Components/StatsComponent.cpp new file mode 100644 index 00000000..579fffbc --- /dev/null +++ b/Source/D1/Components/StatsComponent.cpp @@ -0,0 +1,137 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Components/StatsComponent.h" +#include "Components/StateManagerComponent.h" +#include "Math/UnrealMathUtility.h" + +// Sets default values for this component's properties +UStatsComponent::UStatsComponent() +{ + // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features + // off to improve performance if you don't need them. + PrimaryComponentTick.bCanEverTick = true; + + // ... +} + + +// Called when the game starts +void UStatsComponent::BeginPlay() +{ + Super::BeginPlay(); + + // ... + +} + + +// Called every frame +void UStatsComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + // ... +} + +void UStatsComponent::InitializeStats() +{ + for (auto& stat : BaseStats) + SetCurrentStatValue(stat.Key, stat.Value.BaseValue); +} + +void UStatsComponent::SetCurrentStatValue(EStats stat, float value) +{ + CurrentStats.Add(stat, value); + OnCurrentStatValueUpdated.Broadcast(stat, value); +} + +float UStatsComponent::GetCurrentStatValue(EStats stat) +{ + return *CurrentStats.Find(stat); +} + +void UStatsComponent::ModifyCurrentStatValue(EStats stat, float value, bool bShouldRegenerate) +{ + if (FMath::IsNearlyEqual(value, 0.f)) + return; + + float currentValue = GetCurrentStatValue(stat) + value; + currentValue = FMath::Clamp(currentValue, 0.f, currentValue); + SetCurrentStatValue(stat, currentValue); + + if (bShouldRegenerate) + StartRegen(stat); +} + +void UStatsComponent::TakeDamageOnStat(float inDamage) +{ + float calDamage; + float armor = GetCurrentStatValue(EStats::Armor); + calDamage = (inDamage / (inDamage + armor)) * inDamage; + calDamage = FMath::Clamp(calDamage, 0.f, calDamage); + ModifyCurrentStatValue(EStats::Health, -calDamage); + + FString debugStr = FString::Printf(TEXT("Damage : %d"), calDamage); + GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, debugStr); + + if (GetCurrentStatValue(EStats::Health) <= 0.f) + GetOwner()->GetComponentByClass()->SetCurrentState(ECharacterState::Dead); +} + +void UStatsComponent::StartRegen(EStats statType) +{ + switch (statType) + { + case EStats::None: + break; + case EStats::Health: + break; + case EStats::Stamina: + { + if (GEngine) + { + UWorld* World = GEngine->GetWorldFromContextObjectChecked(this); + if (World) + { + World->GetTimerManager().ClearTimer(RegenTimerHandle); + World->GetTimerManager().SetTimer(RegenTimerHandle, this, &UStatsComponent::RegenerateStamina, 1.5f, true); + } + } + } + break; + case EStats::Armor: + break; + default: + break; + } +} + +void UStatsComponent::RegenerateStamina() +{ + //TODO : ¿©±âºÎÅÍ ½ÃÀÛ +} + +float UStatsComponent::GetBaseStatValue(EStats stat) +{ + + return BaseStats.Find(stat)->BaseValue; +} + +float UStatsComponent::GetMaxStatValue(EStats stat) +{ + return BaseStats.Find(stat)->MaxValue; +} + +void UStatsComponent::SetBaseStatValue(EStats stat, float value) +{ + if (BaseStats.Contains(stat)) + BaseStats.Find(stat)->BaseValue = value; +} + +void UStatsComponent::SetMaxStatValue(EStats stat, float value) +{ + if (BaseStats.Contains(stat)) + BaseStats.Find(stat)->MaxValue = value; +} + diff --git a/Source/D1/Components/StatsComponent.h b/Source/D1/Components/StatsComponent.h new file mode 100644 index 00000000..3e0ab4eb --- /dev/null +++ b/Source/D1/Components/StatsComponent.h @@ -0,0 +1,77 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/ActorComponent.h" +#include "StatsComponent.generated.h" + +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnCurrentStatValueUpdated, EStats, float); + +UENUM(BlueprintType) +enum class EStats : uint8 +{ + None UMETA(DisplayName = "None"), + Health UMETA(DisplayName = "Health"), + Stamina UMETA(DisplayName = "Stamina"), + Armor UMETA(DisplayName = "Armor"), +}; + +USTRUCT(BlueprintType) +struct FBaseStat +{ + GENERATED_BODY() + + FBaseStat() : BaseValue(0.f), MaxValue(0.f) {} + FBaseStat(float InputBaseValue, float InputMaxValue) : BaseValue(InputBaseValue), MaxValue(InputMaxValue) {} + float BaseValue; + float MaxValue; +}; + +UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) +class D1_API UStatsComponent : public UActorComponent +{ + GENERATED_BODY() + +public: + // Sets default values for this component's properties + UStatsComponent(); + +protected: + // Called when the game starts + virtual void BeginPlay() override; + +public: + // Called every frame + virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + +public: + void InitializeStats(); + void SetCurrentStatValue(EStats stat, float value); + float GetCurrentStatValue(EStats stat); + void ModifyCurrentStatValue(EStats stat, float value, bool bShouldRegenerate = true); + void TakeDamageOnStat(float inDamage); + void StartRegen(EStats statType); + void RegenerateStamina(); + +public: + float GetBaseStatValue(EStats stat); + float GetMaxStatValue(EStats stat); + void SetBaseStatValue(EStats stat, float value); + void SetMaxStatValue(EStats stat, float value); + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BaseStats, meta = (AllowPrivateAccess = "true")) + TMap BaseStats; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats, meta = (AllowPrivateAccess = "true")) + TMap CurrentStats; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = StatRegen, meta = (AllowPrivateAccess = "true")) + float StaminaRegenRate; + +private: + FTimerHandle RegenTimerHandle; +private: + FOnCurrentStatValueUpdated OnCurrentStatValueUpdated; +};