BP로 만든 UI -> 캐릭터에서 위젯클래스+위젯 멤버변수 생성 -> 캐릭터정보 및 상태 데이터 - 캐릭터 위젯바인딩
캐릭터 위젯 클래스, 캐릭터 클래스, 캐릭터 데이터 클래스
캐릭터 클래스에서는 위젯클래스를 만들어서 랜더까지
캐릭터 위젯 클래스은 캐릭터데이터에서 HP 데이터를 받고, HP 위젯을 갱신랜더
캐릭터데이터 클래슨는 정보 갱신
캐릭터 위젯 클래스 - 캐릭터 데이터 클래스는 밀접한 관계?

UserWidget을 상속 받아 클래스를 생성한다. 
캐릭터 컴포넌트의 델리게이트 로직을 완성하면, UI에서 캐릭터 컴포넌트에 연결해 HP가 변할 때 마다 프로그레스바를 업데이트하도록 추가
언리얼은 무기 가능한 오차를 측정할떄 KINDA_SMALL_NUMBER라는 매크로를 제공한다

.h
class KGAME_API UABCharacterStatComponent : public UActorComponent
{
public:
    void SetNewLevel(int32 NewLevel);
    void SetDamage(float NewDamage);
    float GetAttack();
    void SetHP(float NewHP);
    float GetHPRatio();

    FOnHPIsZeroDelegete OnHPIsZero;
    FOnHPChangeDelegate OnHpChanged;

  //.cpp
  void UABCharacterStatComponent::SetNewLevel(int32 NewLevel)
{
    ABCHECK(nullptr != ABGameInstance);
    CurrentStatData = ABGameInstance->GetABCharacterData(NewLevel);
    if (nullptr != CurrentStatData)
    {
        Level = NewLevel;
        SetHP(CurrentStatData->MaxHP);
    }
    else
    {
        ABLOG(Error, TEXT("Level (%d) data doesn't exist"), NewLevel);
    }
}


void UABCharacterStatComponent::SetDamage(float NewDamage)
{
    ABCHECK(nullptr != CurrentStatData);
    SetHP(FMath::Clamp<float>(CurrentHP - NewDamage, 0.0f, CurrentStatData->MaxHP));
}

void UABCharacterStatComponent::SetHP(float NewHP)
{
    CurrentHP = NewHP;
    OnHpChanged.Broadcast();

    if (CurrentHP <=KINDA_SMALL_NUMBER)
    {
        CurrentHP = 0.0f;
        OnHPIsZero.Broadcast();
    }
}
float UABCharacterStatComponent::GetHPRatio()
{
    ABCHECK(nullptr != CurrentStatData,0.0f);
    return (CurrentStatData->MaxHP) < KINDA_SMALL_NUMBER ? 0.0f : (CurrentHP / CurrentStatData->MaxHP);
}

언리얼 오브젝트의 약포인터 선언은 TWeakObjectPtr을 사용한다.
캐릭터 위젯은 캐릭터와 생사를 같이 하기 때문에 약포인터의 사용을 필요 없지만, 학습용도로 사용
만약 UI와 캐릭터가 서로 다른 액터라면 약 포인터를 사용하는 것이 좋다

 

//.h
class KGAME_API UABCharacterWidget : public UUserWidget
{
    GENERATED_BODY()

public:
    void BindCharacterStat(class UABCharacterStatComponent* NewCharacterStat);

private:
    TWeakObjectPtr<class UABCharacterStatCompoent> CurrentCharacterStat;
};

//cpp
#include "ABCharacterWidget.h"
#include "ABCharacterStatComponent.h"
void UABCharacterWidget::BindCharacterStat(UABCharacterStatComponent* NewCharacterStat)
{
    ABCHECK(nullptr != NewCharacterStat);
    NewCharacterStat->OnHPChanged.AddLambda([this]()->void {
        if (CurrentCharacterStat.IsValid())
        {
            //ABLOG(Error, TEXT("HPRATIO : %f"), CurrentCharacterStat->GetHpRation());
        }
    });
}

캐릭터의 PostInitializeComponents 함수에서 캐릭터 컴포넌트와 UI 위켓을 연결한다.
이제 캐릭터의 beginplay에서 캐릭터 컴포넌트와 UI를 연결한다. (4.21이후부터)

void AABCharacter::BeginPlay()
{
    Super::BeginPlay();


    auto CharacterWidget = Cast<UABCharacterWidget>(HPBarWidget->GetUserWidgetObject());
    if (nullptr != CharacterWidget)
    {
        CharacterWidget->BindCharacterStat(CharacterStat);
    }

}

완성후 그래프 탭에서 클래스 세팅 버튼을 누른 후 부모클래스가 ABCharacterWidget으로 변경한다.

UI 시스템이 준비되면 NativeConstruct 함수가 호출되는데, UI 생성은 플레이어 컨트롤러의 BeginPlay 전에 호출된 PostinitializeComponents 함수에서 발생한 멸령은 UI에 반영 되지 않는다. 따라서 NativeConstruct 함수에서 위젯 내용을 업데이트하는 로직을 구현하는 것이 필요하다

//h
class KGAME_API UABCharacterWidget : public UUserWidget
{
    GENERATED_BODY()

public:
    void BindCharacterStat(class UABCharacterStatComponent* NewCharacterStat);

protected:
    virtual void NativeConstruct() override;
    void UpdateHPWidget();

private:
    TWeakObjectPtr<class UABCharacterStatComponent> CurrentCharacterStat;

    UPROPERTY()
    class UProgressBar* HPProgressBar;

};


//cpp
#include "ABCharacterWidget.h"
#include "ABCharacterStatComponent.h"
#include "Components/ProgressBar.h"

void UABCharacterWidget::BindCharacterStat(UABCharacterStatComponent* NewCharacterStat)
{
    ABCHECK(nullptr != NewCharacterStat);
    CurrentCharacterStat = NewCharacterStat;
    NewCharacterStat->OnHPChanged.AddUObject(this, &UABCharacterWidget::UpdateHPWidget);

}

void UABCharacterWidget::NativeConstruct()
{
    Super::NativeConstruct();
    HPProgressBar = Cast<UProgressBar>(GetWidgetFromName(TEXT("PB_HPBar")));
    ABCHECK(nullptr != HPProgressBar);
    UpdateHPWidget();
}


void UABCharacterWidget::UpdateHPWidget()
{
    if (CurrentCharacterStat.IsValid())
    {
        if (nullptr != HPProgressBar)
        {

            HPProgressBar->SetPercent(CurrentCharacterStat->GetHPRatio());
        }
    }

}

+ Recent posts