Unreal - 스탯창

2025. 12. 2. 23:30·Unreal 프로젝트 다이어리/두번째 프로젝트

구현내용

게임중 레벨 혹은 재화로 얻는 포인트로 플레이에 영향을 미치는
최대체력, 공격력, 공격속도, 크리티컬확률을 변경할수있는 스탯창
 

구현

이번에는 스탯창을 구현할때 위젯 스위처를 사용하였습니다
위젯스위처의 사용방법은 이와같습니다
 
먼저 위젯스위처를 위젯에 배치한뒤 바인드해줍니다

UPROPERTY(meta = (BindWidget))
class UWidgetSwitcher* WidgetSwitcher_Main;

 
SetActiveWidget 함수로 화면을 전환할수 있습니다

WidgetSwitcher_Main->SetActiveWidget(바인드된 원하는 화면);

 
위젯에서 호버 이벤트로 각각의 모든 버튼함수를 추가하지않고 설계하였습니다

UPROPERTY()
TMap<UButton*, UBorder*> buttonHilightMap;

 
호버중일떄 호버가 끝났을때 Visible / Collapse 해주는 기능입니다
Button -> Border 매핑을 이용하여 맵에 해당하는 모든 버튼에 일괄적으로 작용합니다

void UCubeWidget::NativeConstruct()
{
	Super::NativeConstruct();buttonHilightMap.Add(Button_Strength, Border_MaxHealthHiglight);
	buttonHilightMap.Add(Button_Speed, Border_AttackSpeedHiglight);
	buttonHilightMap.Add(Button_Power, Border_AttackPowerHiglight);
	buttonHilightMap.Add(Button_Critical, Border_CriticalRateHiglight);
	buttonHilightMap.Add(Button_StrengthReturn, Border_MaxHealthHiglight);
	buttonHilightMap.Add(Button_SpeedReturn, Border_AttackSpeedHiglight);
	buttonHilightMap.Add(Button_PowerReturn, Border_AttackPowerHiglight);
	buttonHilightMap.Add(Button_CriticalReturn, Border_CriticalRateHiglight);
	for (auto& hilightMapPair : buttonHilightMap)
	{
		if (hilightMapPair.Key)
		{
			hilightMapPair.Key->OnHovered.AddDynamic(this, &UCubeWidget::HoverButtonHilight);
			hilightMapPair.Key->OnUnhovered.AddDynamic(this, &UCubeWidget::UnHoverButtonHilight);
		}
	}
}
void UCubeWidget::HoverButtonHilight()
{
	UButton* callHilightButton = nullptr;
	for (auto& hilightPair : buttonHilightMap)
	{
		if (hilightPair.Key->IsHovered())
		{
			callHilightButton = hilightPair.Key;
			break;
		}
	}
	if (!callHilightButton)
		return;
	currentHilightButton = callHilightButton;
	if (UBorder* borderHilight = buttonHilightMap[callHilightButton])
		borderHilight->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
}

void UCubeWidget::UnHoverButtonHilight()
{
	if (!currentHilightButton)
		return;

	if (buttonHilightMap.Contains(currentHilightButton))
	{
		if (UBorder* hilightBorder = buttonHilightMap[currentHilightButton])
			hilightBorder->SetVisibility(ESlateVisibility::Collapsed);
	}
	currentHilightButton = nullptr;
}

 
다음은 업그레이드 타입 분간법입니다

UENUM(BlueprintType)
enum class EUpgradeType : uint8
{
	Strength,
	Speed,
	Power,
	Critical
};

 
타입별 업그레이드 공식입니다

void UStatComponent::ApplyStatUpgrade(EUpgradeType type)
{
	if (currentStatPoint <= 0)
		return;

	currentStatPoint--;
	UpdateStatPointUI();

	switch (type)
	{
	case EUpgradeType::Strength:
		statUpgradeStrength++;
		needLacrimaCount += needUpgradeLacrimaCount;
		AddEntryBonus(EBaseStatType::Hp, 10.f);
		break;
	case EUpgradeType::Speed:
		statUpgradeSpeed++;
		needLacrimaCount += needUpgradeLacrimaCount;
		AddEntryBonus(EBaseStatType::AttackSpeed, 0.01f);
		break;
	case EUpgradeType::Power:
		statUpgradePower++;
		needLacrimaCount += needUpgradeLacrimaCount;
		AddEntryBonus(EBaseStatType::AttackPower, 5.f);
		break;
	case EUpgradeType::Critical:
		statUpgradeCritical++;
		needLacrimaCount += needUpgradeLacrimaCount;
		AddEntryBonus(EBaseStatType::CriticalRate, 0.01f); //1프로
		break;
	default:
		break;
	}
	onStatUpgradePointChanged.Broadcast(statUpgradeStrength, statUpgradeSpeed, statUpgradePower, statUpgradeCritical);
}

 
UI 델리게이트 호출법입니다
먼저 매개변수로 호출될 갯수에 따라 파라미터에 맞는 델리게이트를 선언해줍니다
이런식으로 사용합니다

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAttackPowerChanged, float, current, float, total);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAttackSpeedChanged, float, current, float, total);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnCriticalRateChanged, float, current, float, total);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLevelChanged, int32, level);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnLacrimaChanged, int32, current, int32, needCount);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOnStatUpgradePointChanged, int32, upgradeStrength, int32, upgradeSpeed, int32, upgradePower, int32, upgradeCritical);

 
사용할 델리게이트 멤버 변수를 선언해줍니다
이벤트를 전달해주는 변수입니다

UPROPERTY()
FOnStatPointChanged onStatPointChanged;

UPROPERTY()
FOnAbilityPointChanged onAbilityPointChanged;

UPROPERTY()
FOnAttackPowerChanged onAttackPowerChanged;

UPROPERTY()
FOnAttackSpeedChanged onAttackSpeedChanged;

UPROPERTY()
FOnCriticalRateChanged onCriticalRateChanged;

UPROPERTY()
FOnLevelChanged onLevelChanged;

 
UI가 업데이트 되어야할시점에 델리게이트에 등록된 모든 함수를 호출하고 매개변수값을 전달합니다
즉 델리게이트를 통해 이벤트를 발생시킵니다 즉 구독 해 놓은 모든 수신자가 호출되는 구조입니다

onLevelChanged.Broadcast(level);
onExpChanged.Broadcast(currentExp, expNextLevel, level);

 
해당 브로드캐스트로 수신자가 호출되면 수신자를 등록하는 즉 델리게이트를 등록해야만합니다
원하는 위젯에서 이와같이 해주시면됩니다
이렇게 하면 수신자들은 알아서 해당 함수를 호출하고 원하는 작동을 할수있게 됩니다

APlayerController* pc = GetOwningPlayer();
APawn* myPawn = pc->GetPawn();
statComp = myPawn->FindComponentByClass<UStatComponent>();

statComp->onHpChanged.AddDynamic(this, &UCubeWidget::UpdateHpText);
statComp->onAttackPowerChanged.AddDynamic(this, &UCubeWidget::UpdateAttackPowerText);
statComp->onAttackSpeedChanged.AddDynamic(this, &UCubeWidget::UpdateAttackSpeedText);

 

회고록

이번편은 UI를 다루는편이라 스탯관련 변수와 함수가 너무 많기도 하고 일일히 하나씩 기록하기에는
너무 많고 난잡해질꺼같아 UI쪽만 다루겠습니다
 

결과

UI

스위처 1번

 
스위처 2번
UI를 막 넣는게 아니고 하나하나 값들을바인딩 해주고 가로와 세로 비율을 맞춰서 작업하니 하이어라키가
상당히 길어지고 복잡해졌으나 완성품은 확실하게 나왔다

규칙은 이와 같습니다

  1. 해당 스탯 강화버튼을 누르면 캐릭터의 기본 능력치가 강화됩니다
  2. 레벨업을 하면 강화가능포인트를 얻으며 별도로 라크리마 포인트가 존재하는데 1강화당 300 라크리마가 필요합니다
  3. 라크리마 포인트가 부족하면 적용하기를 눌러도 누르기전의 상태로 롤백되며 적용되지않습니다
  4. 적용하기버튼을 눌러야만 실제 스탯이 변경됩니다
  5. 해당 버튼에 마우스를 가져다대면 상승되는 기본 능력의 보더가 강조됩니다

 
버튼을 눌러 능력수치를 올리거나 내릴수 있습니다

 
해당 능력강화창 버튼위에 마우스가 호버되면 변화되는 능력치창의 색이 변경됩니다

현재 라크리마 보유량이 강화 필요량 라크리마 보유량 보다 적으면 강화되지않고 롤백됩니다

 
 

 

저작자표시 비영리 변경금지 (새창열림)

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

Unreal - Blood Decal (피 튀기기)  (0) 2025.12.10
Unreal - 스킬 트리  (0) 2025.12.10
Unreal - 세이브 게임  (0) 2025.12.02
Unreal - 경험치, 레벨업 구현하기  (0) 2025.12.02
Unreal - 데미지 오버레이  (0) 2025.12.01
'Unreal 프로젝트 다이어리/두번째 프로젝트' 카테고리의 다른 글
  • Unreal - Blood Decal (피 튀기기)
  • Unreal - 스킬 트리
  • Unreal - 세이브 게임
  • Unreal - 경험치, 레벨업 구현하기
lucodev
lucodev
커피와 노트북 그리고 개발
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (210) N
      • Unreal 프로젝트 다이어리 (107) N
        • 첫번째 프로젝트 (73)
        • 두번째 프로젝트 (34) 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)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

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

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

티스토리툴바