설비 제작 UI 구조
설비 제작 UI는 크게 세 가지 위젯으로 나누어 구성했다.
첫 번째는 전체 제작 창을 담당하는 FactoryCraftWidget이다. 이 위젯은 제작 가능한 설비 목록을 만들고, 선택된 설비의 상세 정보와 필요 재료 목록, 제작 버튼 상태를 관리한다.
두 번째는 설비 목록의 한 줄을 담당하는 FactoryCraftEntryWidget이다. 설비 이름과 아이콘을 표시하고, 버튼 클릭 시 어떤 설비가 선택되었는지 상위 위젯에 전달한다.
세 번째는 제작 비용의 한 줄을 담당하는 FactoryCraftCostEntryWidget이다. 필요한 아이템의 아이콘, 이름, 현재 보유 개수와 필요 개수를 표시한다.
제작 가능한 설비 목록 생성
설비 목록은 RebuildFactoryList()에서 다시 만든다. 먼저 LoadSubsystem을 통해 제작 가능한 설비 ID 목록을 가져오고, 그 ID들을 순회하면서 설비 엔트리 위젯을 생성한다.
설비 목록을 가져올 때는 다음 흐름을 사용했다.
FKOBuildMenuQuery Query;
TArray<FName> FactoryIds;
LoadSub->GetBuildableFactoryIds(Query, FactoryIds);
여기서 Query는 설비 목록을 가져올 때 사용할 조건값이다. 현재는 별도 조건을 넣지 않았기 때문에 기본 조건으로 제작 가능한 설비를 가져온다.
FactoryIds는 결과를 담는 배열이다. GetBuildableFactoryIds()가 조건에 맞는 설비 ID들을 이 배열에 채워 넣는다.
이후에는 FactoryIds를 순회하면서 각 설비의 데이터 행을 찾고, 해당 정보를 바탕으로 목록 위젯을 생성한다.
for (const FName FactoryId : FactoryIds)
{
const FKOFactoryRow* Row = LoadSub->FindFactoryRow(FactoryId);
...
}
즉, 제작 UI는 설비 데이터를 직접 전부 들고 있는 것이 아니라, 먼저 설비 ID 목록을 받은 뒤 ID를 기준으로 실제 데이터 테이블 행을 조회하는 방식으로 동작한다.
선택된 설비 상세 정보 표시
설비 목록에서 특정 엔트리를 클릭하면 해당 설비 ID가 SelectedFactoryId에 저장된다.
void UKOFactoryCraftWidget::HandleFactoryEntryClicked(FName InFactoryId)
{
SelectedFactoryId = InFactoryId;
RefreshDetail();
}
그 후 RefreshDetail()을 호출하여 오른쪽 상세 영역을 갱신한다. 상세 영역에는 선택된 설비의 아이콘, 이름, 설명, 현재 보유 개수가 표시된다.
보유 개수는 인벤토리 컴포넌트에서 가져온다.
const int32 OwnedCount = Inventory ? Inventory->GetCountOf(SelectedFactoryId) : 0;
이렇게 해서 플레이어가 이미 해당 설비를 몇 개 가지고 있는지 UI에서 바로 확인할 수 있게 했다.
제작 비용 목록 생성
선택된 설비의 제작 비용은 RebuildCostList()에서 만든다.
설비 데이터의 CraftCosts를 순회하면서 필요한 아이템 태그와 개수를 읽는다. 이때 제작 비용은 아이템 ID가 아니라 GameplayTag로 들어 있기 때문에, 먼저 태그를 실제 아이템 ID로 변환한다.
const FName ItemId = LoadSub->FindItemIdByTag(Cost.Key);
그다음 인벤토리에서 해당 아이템의 보유 개수를 가져온다.
const int32 OwnedCount = Inventory->GetCountOf(ItemId);
그리고 아이템 이름과 아이콘을 가져와 FactoryCraftCostEntryWidget에 전달한다.
CostEntry->SetupCost(
ItemName,
ItemIcon,
OwnedCount,
RequiredCount
);
재료 엔트리 위젯에서는 보유 개수 / 필요 개수 형식으로 표시하고, 재료가 부족하면 개수 텍스트를 빨간색으로 보여준다.
const bool bEnough = InOwnedCount >= InRequiredCount;
CountText->SetColorAndOpacity(
bEnough
? FSlateColor(FLinearColor::Black)
: FSlateColor(FLinearColor::Red)
);
이렇게 해서 플레이어가 어떤 재료가 부족한지 바로 알 수 있게 했다.
제작 가능 여부 검사
제작 버튼은 현재 선택된 설비를 제작할 수 있을 때만 활성화된다.
제작 가능 여부는 CanCraftFactory()에서 검사한다. 이 함수는 선택된 설비의 제작 비용을 모두 확인하고, 인벤토리에 각 재료가 충분히 있는지 검사한다.
if (!Inventory->HasEnoughItems(ItemId, Cost.Value))
{
return false;
}
하나라도 부족하면 false를 반환하고, 모든 재료가 충분하면 true를 반환한다.
제작 버튼은 이 결과에 따라 활성화된다.
CraftButton->SetIsEnabled(CanCraftFactory(SelectedFactoryId));
이 구조 덕분에 제작할 수 없는 상태에서는 버튼 자체가 비활성화되어 잘못된 제작 시도를 줄일 수 있다.
실제 제작 처리와 재료 차감
제작 버튼을 누르면 CraftSelectedFactory()가 실행된다.
먼저 데이터와 인벤토리, 선택된 설비 ID가 유효한지 확인하고, 다시 한 번 제작 가능 여부를 검사한다. 그 후 필요한 재료를 하나씩 차감한다.
if (!Inventory->TryRemoveItem(ItemId, Cost.Value))
{
...
}
여기서 TryRemoveItem()은 인벤토리에서 해당 아이템을 필요한 개수만큼 제거하려고 시도하는 함수다. 앞에 !가 붙어 있기 때문에, 이 조건문은 재료 차감에 실패했을 때 실행된다.
재료를 차감하는 도중 실패할 수도 있기 때문에, 이미 차감한 재료는 RemovedItems 배열에 저장해둔다.
RemovedItems.Add(TPair<FName, int32>(ItemId, Cost.Value));
만약 중간에 차감 실패가 발생하면 이전에 차감했던 재료를 다시 복구한다.
for (const TPair<FName, int32>& Removed : RemovedItems)
{
Inventory->TryAddItem(EKOSlotKind::Item, Removed.Key, Removed.Value);
}
이 부분은 제작 처리에서 중요한 안전장치다. 여러 재료를 차감하는 중간에 문제가 생겼을 때 일부 재료만 사라지는 상황을 막을 수 있다.
재료 차감이 모두 성공하면 설비를 인벤토리에 추가한다.
const int32 Remaining = Inventory->TryAddItem(
EKOSlotKind::Factory,
SelectedFactoryId,
1
);
만약 설비 지급에 실패하면 이때도 차감했던 재료를 다시 복구한다. 제작 성공 후에는 Refresh()를 호출해 UI를 갱신한다.
정리
제작 가능한 설비 목록을 데이터 기반으로 생성하고, 선택된 설비의 상세 정보와 제작 비용을 표시하며, 인벤토리 재료를 검사해 제작 가능 여부를 판단하는 구조까지 구현했다.
이후에는 플레이어가 제작 개수를 직접 지정하여 제작할 수 있는 기능을 추가할 예정이다.
'Unreal 최종 팀프로젝트' 카테고리의 다른 글
| [TIL] UI 구조 개선 | 최종 팀프로젝트 (0) | 2026.06.19 |
|---|---|
| [TIL] 개수 지정 제작 기능 | 최종 팀프로젝트 (0) | 2026.06.15 |
| [TIL] 무기 장착 슬롯 | 최종 팀프로젝트 (0) | 2026.06.10 |
| [TIL] 레시피 슬롯 생성 | 최종 팀프로젝트 (0) | 2026.06.09 |
| [TIL] 맵, 미니맵 | 최종 팀프로젝트 (0) | 2026.06.08 |