Unreal - StatComponent

2025. 11. 21. 04:41·Unreal 프로젝트 다이어리/두번째 프로젝트

구현이유

플레이어의 기본 스탯(Base Stat), 버프/디버프, 힐(회복), 피해 처리(GetDamage) 등
캐릭터 능력치와 관련된 모든 기능을 하나의 모듈로 통합하고 재사용이 가능하도록 하기 위해
플레이어에 StatComponent를 별도로 붙여서 관리하도록 설계했다.

 

구현방식

플레이어의 기본 스탯(BaseStat) 을 데이터테이블에서 불러와 레벨에 따라 계산하고,
버프·디버프(EntryBonus, EntryRate) 및 데미지/회복/체간게이지(Posture) 처리

로직을 하나의 StatComponent에 모듈화했으며,
데이터 테이블에서 가져온 기본 스탯을 ApplyLevelStat 함수로 레벨 성장 공식에 따라

재계산해 entryBase에 설정하고 각 스탯은

EntryTotal() = base * ( 1 + rate ) + bonus 공식을 통해 버프 / 디버프 가 반영된 최종값을 산출

합연산과 곱연산을 구축하였다

또한 플레이어가 데미지를 받을때의 GetDamage함수를 직접만들기위해

"가드" 라는시스템이 존재하기때문에 가드 상황에 맞게 체간게이지, 받는데미지를 다르게 계산해주었다.

 

StatComponent는 TMap 기반의 스탯 저장 구조와
레벨 성장·버프/디버프·가드 처리 알고리즘을 조합한
모듈형 스탯 시스템으로 설계하였습니다

 

UENUM(BlueprintType)
enum class EGuardType : uint8
{
	None UMETA(DisplayName = "None"),
	Normal UMETA(DisplayName = "Normal"),
	Perfect UMETA(DisplayName = "Perfect"),
};

struct FGuardModifier
{
	float damageRate;
	float postureRate;
};

static const TMap<EGuardType, FGuardModifier> guard_Modifiers =
{
	{EGuardType::None, {1.f, 0.1f}},
	{EGuardType::Normal, {0.5f, 0.5f}},
	{EGuardType::Perfect,{0.f, 0.05f}}
};

UENUM(BlueprintType)
enum class EBaseStatType : uint8
{
	Hp,
	Posture,
	AttackPower,
	PostureRecoverySpeed
};

//엔트리 계산식 : base + bonus + rate
USTRUCT(BlueprintType)
struct FStatEntry
{
	GENERATED_BODY()

	UPROPERTY(VisibleAnywhere)
	float entryBase = 0.f;

	UPROPERTY(VisibleAnywhere)
	float entryBonus = 0.f;

	UPROPERTY(VisibleAnywhere)
	float entryRate = 0.f;

	float EntryTotal() const
	{
		return (entryBase * (1.f + entryRate)) + entryBonus;
	}
};

 

데이터테이블에서 기본 스탯을 불러와 레벨 성장 공식을 적용해 EntryBase 값을 설정하고 현재 Hp/Posture을 초기화하며

UpdateCurrentStats에서 현재 Hp/Posture를 최종 스탯(EntryTotal)기준으로 클램핑하여

변화가 있으면 델리게이트로 UI에 갱신을 전달

void UStatComponent::ApplyLevelStat()
{
	float hpGrowthRate = 50.f;
	float attackGrowthRate = 5.f;
	float postureRecoveryGrowthRate = 0.5f;
	float exponent = 1.1f;

	stats.FindOrAdd(EBaseStatType::Hp).entryBase = CalculateLevelStat(cachedBaseStat.baseHp, level, hpGrowthRate, exponent);
	stats.FindOrAdd(EBaseStatType::AttackPower).entryBase =CalculateLevelStat(cachedBaseStat.baseAttackPower, level, attackGrowthRate, exponent);

	// Posture는 기본값, RecoverySpeed는 선형 증가
	stats.FindOrAdd(EBaseStatType::Posture).entryBase = cachedBaseStat.basePosture;
	stats.FindOrAdd(EBaseStatType::PostureRecoverySpeed).entryBase = cachedBaseStat.basePostureRecoverySpeed + postureRecoveryGrowthRate * (level - 1);

	currentHp = stats[EBaseStatType::Hp].EntryTotal();
	currentPosture = 0.f;
	UpdateCurrentStats();
}

void UStatComponent::InitStats()
{
	if (!characterBaseTable)
		return;

	const FString ContextString(TEXT("Character Base Stats"));
	FCharacterBaseStat* baseStat = characterBaseTable->FindRow<FCharacterBaseStat>(FName("BaseStat"), ContextString);

	cachedBaseStat = *baseStat;
	ApplyLevelStat();
}

void UStatComponent::UpdateCurrentStats()
{
	if (stats.Contains(EBaseStatType::Hp))
		currentHp = FMath::Clamp(currentHp, 0.f, stats[EBaseStatType::Hp].EntryTotal());

	// Posture
	if (stats.Contains(EBaseStatType::Posture))
		currentPosture = FMath::Clamp(currentPosture, 0.f, stats[EBaseStatType::Posture].EntryTotal());

	if (onHpChanged.IsBound())
		onHpChanged.Broadcast(currentHp, stats[EBaseStatType::Hp].EntryTotal());

	if (onPostureChanged.IsBound())
		onPostureChanged.Broadcast(currentPosture, stats[EBaseStatType::Posture].EntryTotal());

}

 

구현한 합연산 및 곱연산입니다

//---------------------------buff----------------------
//고정값 + 계산식
void UStatComponent::AddEntryBonus(EBaseStatType statType, float amount)
{
	if (stats.Contains(statType))
	{
		stats[statType].entryBonus += amount;
		UpdateCurrentStats();
	}
}

//퍼센트 보너스 비율 증가 계산식
void UStatComponent::AddEntryRate(EBaseStatType statType, float rateAmount)
{
	if (stats.Contains(statType))
	{
		stats[statType].entryRate += rateAmount;
		UpdateCurrentStats();
	}
}

 

구현한 데미지를 받는 함수입니다

피격시 체력과 체간게이지를 감소.증가 계산하는 함수로 

가드종류에 따라 미리 정의된 데미지비율 / 자세 증가 비율을 적용해 체력을 깎고 체간은 증가시킵니다

void UStatComponent::ApplyGetDamage(float damageAmount, EGuardType guardType)
{
	const FGuardModifier* guardModifier = guard_Modifiers.Find(guardType);
	currentHp -= damageAmount * guardModifier->damageRate;
	currentPosture += damageAmount * guardModifier->postureRate;
	UpdateCurrentStats();
}

 

캐릭터 Base스탯값을 가지고있는 데이터테이블입니다

Level1기준으로 플레이어가 가진 기본 스탯 값들로 이루어져있으며 시작시 이와같은 값들로 초기화됩니다

 

 

구조를 보기쉽게 다이어그램으로 변환해봤습니다

'Unreal 프로젝트 다이어리 > 두번째 프로젝트' 카테고리의 다른 글

Unreal - 인벤토리(1) ( 크기변경하기, 창옮기기 )  (2) 2025.11.22
Unreal - UI (HpWidget, PostureWidget)  (0) 2025.11.21
Unreal - 상호작용(사다리 타기)  (0) 2025.11.15
Unreal - 상호작용(승강기)  (0) 2025.11.12
Unreal - 상호작용(Edge Traversal)  (0) 2025.11.09
'Unreal 프로젝트 다이어리/두번째 프로젝트' 카테고리의 다른 글
  • Unreal - 인벤토리(1) ( 크기변경하기, 창옮기기 )
  • Unreal - UI (HpWidget, PostureWidget)
  • Unreal - 상호작용(사다리 타기)
  • Unreal - 상호작용(승강기)
lucodev
lucodev
커피와 노트북 그리고 개발
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (211) N
      • Unreal 프로젝트 다이어리 (108) N
        • 첫번째 프로젝트 (73)
        • 두번째 프로젝트 (35) N
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 (52)
        • Stack,Queue (7)
        • Hash (4)
        • Heap (2)
        • Sort (5)
        • Exhaustive search (5)
        • Greedy (2)
        • BFS , DFS (7)
        • Graph (2)
        • Dynamic Programming (1)
        • C++ Math (2)
        • 기타 문제 (14)
      • C++ 백준 (4)
      • C++ 팁 (1)
      • 개인 코테 & 스타디 <비공개> (29)
        • 코드 개인보관함 (9)
        • 코딩테스트+@ (11)
        • 알고리즘 스타디 (6)
        • 알고리즘 스타디 과제 (3)
        • 비공개 (0)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 태그

    언리얼 프로그래스바
    언리얼 motionmatching
    언리얼 모션매칭
    언리얼 인벤토리
    언리얼 ui
    unreal 모션매칭
    언리얼 behaviortree
    Unreal Parkour
    unreal inventory
    언리얼 시퀀스
    unreal 인벤토리
    언리얼 파쿠르
    언리얼 parkour
    언리얼 behavior tree
    언리얼
    unreal 시퀀스
    언리얼 비헤이비어트리
    언리얼 컷씬
    언리얼 상호작용
    unreal 파쿠르
  • hELLO· Designed By정상우.v4.10.3
lucodev
Unreal - StatComponent
상단으로

티스토리툴바