오늘은 룬 시스템의 스탯창에서 총합 계산이 잘못되는 버그를 해결했음
처음엔 수학 계산 오류인 줄 알았는데 알고 보니 언리얼 위젯의 생명주기를 제대로 이해하지 못해서 생긴 문제였음
스탯 패널 UI를 구현하고 테스트하니까 뭔가 이상했음

그리드를 처음 로드했을 때 이미 배치된 룬이 있는 경우 해당 스탯은 총합이 제대로 된 결과가 나오지 않았고, 룬을 배치했을 때 기존 베이스 스탯이 빠진 룬 효과만 반영되는 문제가 발생
위젯을 생성하고 InitStat()을 해줄 때 분명히 100으로 설정되는데 왜 0이 나오는지 이해할 수 없었음
로그를 찍어보니 값이 설정되는 순서가 예상과 달랐음
문제가 된 호출 순서:
1. CreateWidget() → 위젯 생성
2. InitStat(BaseValue = 100) → 올바른 값 설정
3. AddChild() → 위젯을 화면에 추가
4. NativeConstruct(BaseValue = 0) → 값이 리셋됨!
5. UpdateUI() → 잘못된 계산 (0 + 20 = 20)
// 문제가 된 코드
void UGS_StatDataWidget::InitStat(FName InStatName, float InBaseValue)
{
StatName = InStatName;
BaseValue = InBaseValue; // 여기서는 100 설정
UE_LOG(LogTemp, Warning, TEXT("InitStat: %s = %.1f"), *StatName.ToString(), BaseValue);
}
void UGS_StatDataWidget::NativeConstruct()
{
Super::NativeConstruct();
BaseValue = 0.0f; // 여기서 0으로 리셋됨!
CurrRuneValue = 0.0f;
CurrBonusValue = 0.0f;
}
핵심 깨달음:
NativeConstruct()는 위젯이 화면에 나타날 때 호출됨 (AddChild 이후)InitStat()은 개발자가 직접 호출하는 함수 (AddChild 이전)InitStat()에서 설정한 값이 NativeConstruct()에서 덮어써짐단계별로 어디서 값이 변하는지 추적해봤음
void UGS_StatDataWidget::InitStat(FName InStatName, float InBaseValue)
{
StatName = InStatName;
BaseValue = InBaseValue;
UE_LOG(LogTemp, Warning, TEXT("InitStat: %s = %.1f"), *StatName.ToString(), BaseValue);
}
void UGS_StatDataWidget::NativeConstruct()
{
UE_LOG(LogTemp, Warning, TEXT("NativeConstruct 호출 - BaseValue: %.1f"), BaseValue);
BaseValue = 0.0f; // 문제 지점!
UE_LOG(LogTemp, Warning, TEXT("NativeConstruct 후 - BaseValue: %.1f"), BaseValue);
}
void UGS_StatDataWidget::UpdateUI()
{
UE_LOG(LogTemp, Warning, TEXT("UpdateUI - BaseValue: %.1f"), BaseValue);
float TotalVal = BaseValue + CurrRuneValue + CurrBonusValue;
UE_LOG(LogTemp, Warning, TEXT("총합: %.1f + %.1f + %.1f = %.1f"),
BaseValue, CurrRuneValue, CurrBonusValue, TotalVal);
}
결과 로그:



가장 큰 교훈
언리얼 위젯의 생명주기를 제대로 이해하지 못하면 예상치 못한 버그가 생김. 특히 NativeConstruct()는 위젯이 화면에 나타날 때 호출되므로, 개발자가 직접 호출하는 초기화 함수와 순서가 꼬일 수 있음
설계 개선사항
1. Constructor() → 위젯 인스턴스 생성
2. NativePreConstruct() → 에디터에서 미리보기용
3. NativeConstruct() → 위젯이 화면에 추가될 때 ⚠️
4. NativeTick() → 매 프레임 (필요시)
5. NativeDestruct() → 위젯이 제거될 때
NativeConstruct: 위젯이 화면에 추가될 때 호출 (AddChild 시점)
개발자 함수: CreateWidget 직후에 호출 가능
호출 순서: CreateWidget → 개발자 함수 → AddChild → NativeConstruct