1. 핵심 설계 원칙
- Single Source of Truth: 모든 데이터는 컴포넌트 내의 TArray 혹은 TMap에서 관리하며, UI는 이를 관찰(Observe)하여 출력만 수행합니다.
- Defensive Programming: 잘못된 인덱스, 유효하지 않은 스킬 ID, 중복 장착 시도를 로직 입구에서 return으로 차단합니다.
2. 상세 코드 구현 (C++)
① 중복 장착 방지 및 인벤토리 → 슬롯 배치
인벤토리에서 스킬을 끌어다 놓을 때, 이미 다른 슬롯에 해당 스킬이 있는지 검사하는 것이 핵심입니다.
C++
/**
* 인벤토리에서 슬롯으로 스킬을 장착합니다.
* @param SkillID 인벤토리에서 선택한 스킬의 고유 ID
* @param TargetSlotIndex 장착하고자 하는 퀵슬롯의 번호 (0~3)
*/
bool UT3SkillComponent::EquipSkillFromInventory(int32 SkillID, int32 TargetSlotIndex)
{
// 1. 인덱스 유효성 검사 (시니어의 기본기: 방어적 코딩)
if (!EquippedSkills.IsValidIndex(TargetSlotIndex))
{
UE_LOG(LogTemp, Warning, TEXT("Invalid Slot Index: %d"), TargetSlotIndex);
return false;
}
// 2. 중복 장착 확인 (이미 장착된 스킬인지 루프 검사)
for (int32 i = 0; i < EquippedSkills.Num(); ++i)
{
if (EquippedSkills[i].SkillID == SkillID)
{
UE_LOG(LogTemp, Log, TEXT("Skill %d is already equipped in slot %d"), SkillID, i);
// [심화] 이미 있다면 기존 위치를 비우거나 스왑할지 결정
// 여기선 안전하게 중복 등록을 거부함
return false;
}
}
// 3. 데이터 자산(Data Asset)에서 스킬 정보 가져오기
FSkillData* NewSkillData = GetSkillDataByID(SkillID); // 앞서 만든 함수 활용
if (NewSkillData)
{
// 4. 슬롯에 데이터 할당 (값 복사 발생)
EquippedSkills[TargetSlotIndex] = *NewSkillData;
// 5. UI 동기화를 위한 델리게이트 브로드캐스트
OnSkillSlotChanged.Broadcast(TargetSlotIndex, EquippedSkills[TargetSlotIndex]);
return true;
}
return false;
}
② 슬롯 간 스왑 (Slot-to-Slot Swap)
장착된 스킬끼리 위치를 바꿀 때는 데이터 유실이 없도록 임시 저장 공간을 활용해야 합니다.
C++
/**
* 장착된 스킬 슬롯 간의 위치를 교체합니다.
*/
void UT3SkillComponent::SwapSkills(int32 SourceIndex, int32 TargetIndex)
{
if (!EquippedSkills.IsValidIndex(SourceIndex) || !EquippedSkills.IsValidIndex(TargetIndex)) return;
// Triple-Buffered Swap 로직
FSkillData TempData = EquippedSkills[SourceIndex];
EquippedSkills[SourceIndex] = EquippedSkills[TargetIndex];
EquippedSkills[TargetIndex] = TempData;
// 두 슬롯이 모두 변했으므로 각각 브로드캐스트
OnSkillSlotChanged.Broadcast(SourceIndex, EquippedSkills[SourceIndex]);
OnSkillSlotChanged.Broadcast(TargetIndex, EquippedSkills[TargetIndex]);
UE_LOG(LogTemp, Log, TEXT("Swapped Slot %d and %d"), SourceIndex, TargetIndex);
}
3. UI 동기화 (C++ 기반 UserWidget)
UI에서 NativeConstruct를 통해 초기화 시점에 데이터를 긁어오는 상세 로직입니다.
C++
void USkillWidget::NativeConstruct()
{
Super::NativeConstruct();
if (APlayerController* PC = GetOwningPlayer())
{
// 캐릭터를 통해 스킬 컴포넌트 접근
if (AT3CharacterBase* Char = Cast<AT3CharacterBase>(PC->GetPawn()))
{
SkillComp = Char->GetSkillComponent();
if (SkillComp)
{
// 1. 변화가 생길 때 실행될 함수 바인딩
SkillComp->OnSkillSlotChanged.AddDynamic(this, &USkillWidget::UpdateSlotUI);
// 2. [중요] 초기화: 현재 컴포넌트가 가진 데이터를 UI 슬롯에 전부 뿌려줌
SyncAllSlots();
}
}
}
}
void USkillWidget::SyncAllSlots()
{
if (!SkillComp) return;
// 컴포넌트의 배열을 순회하며 각 슬롯(Child Widget) 업데이트
for (int32 i = 0; i < SkillComp->GetMaxSlotCount(); ++i)
{
FSkillData Data;
if (SkillComp->GetSkillDataInSlot(i, Data)) // 참조로 안전하게 데이터 가져오기
{
UpdateSlotUI(i, Data);
}
}
}
'언리얼엔진5 공부' 카테고리의 다른 글
| [TIL] UE5 나이아가라 잔상 시스템 및 AI 협동 분신 구현 (0) | 2026.03.08 |
|---|---|
| [TIL]UE 5 '신의 심판' 스킬 시스템 구현 (0) | 2026.02.20 |
| [TIL] UE5 콜리젼 & 오버랩 초기화 순서에 따른 이슈 (0) | 2026.02.09 |
| [TIL] UE5 컴포넌트 기반 스킬/아이템 슬롯 시스템 설계 및 구현 (1) | 2026.02.05 |
| [TIL] Unreal Engine 5: 동적 록온 시스템 및 적응형 카메라 연출 (2) | 2026.02.04 |