[박치영] Stat Component 작업 중

main
PCYPC\pcy35 2023-08-10 19:06:02 +09:00
parent 5706b3a1bf
commit 312cf74de4
12 changed files with 189 additions and 26 deletions

Binary file not shown.

Binary file not shown.

View File

@ -9,7 +9,8 @@
"Type": "Runtime",
"LoadingPhase": "Default",
"AdditionalDependencies": [
"Engine"
"Engine",
"UMG"
]
}
],

View File

@ -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;

View File

@ -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;
};

View File

@ -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())

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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()
{
}

View File

@ -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;
};