구현내용
게임중 레벨 혹은 재화로 얻는 포인트로 플레이에 영향을 미치는
최대체력, 공격력, 공격속도, 크리티컬확률을 변경할수있는 스탯창
구현
이번에는 스탯창을 구현할때 위젯 스위처를 사용하였습니다
위젯스위처의 사용방법은 이와같습니다
먼저 위젯스위처를 위젯에 배치한뒤 바인드해줍니다
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강화당 300 라크리마가 필요합니다
- 라크리마 포인트가 부족하면 적용하기를 눌러도 누르기전의 상태로 롤백되며 적용되지않습니다
- 적용하기버튼을 눌러야만 실제 스탯이 변경됩니다
- 해당 버튼에 마우스를 가져다대면 상승되는 기본 능력의 보더가 강조됩니다
버튼을 눌러 능력수치를 올리거나 내릴수 있습니다

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

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

'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 |