포스트

구현계획 — 인벤토리과제

구현계획 — 인벤토리과제

언리얼 마스터 과제 — 인벤토리 시스템 구현계획

프로젝트 경로: D:\Unreal\NBC_JangSik_Inv
구조: Character 직접 구현 (Component 분리 없음)
참고 챕터: 1-7(리플렉션) · 3-1(아이템 설계) · 3-3(데이터 관리) · 4-1(UMG)

https://forms.gle/3bsrYWXDyjBp8hnB8 [과제 내용]

##필수 과제

-가방은 TArray를 통해서 만드세요

  • -TMap은 저희 TArray에 담긴 아이템들을 확인하게 되면 그 아이템 정보를 Key값으로 아이템 정보들이 뜨도록 만들어주시세요.
  • -TSet은 칭호 획득을 사용하시면됩니다.
  • -해당 칭호가 있어야 아이템을 사용할 수 있도록 만들어주세요.

##도전 과제

  • UI를 통해서 비주얼로 확인할 수 있도록 만들어주세요

STEP 1 — FItem 구조체 + Character 헤더 선언

챕터1-7 USTRUCT/UPROPERTY 패턴, 챕터3-1 ItemType(FName) 패턴 적용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// InvCharacter.h 상단 (generated.h 직전)
USTRUCT(BlueprintType)
struct FItem
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    FString Name;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    FString Desc;

    // FName 사용 (챕터3-1 ItemType 패턴) — TSet<FName> OwnedTitles와 타입 일치
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    FName RequiredTitle;  // NAME_None = 칭호 조건 없음
};

Character 헤더 멤버 선언:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 필수 1 — 가방
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Inventory")
TArray<FItem> Bag;

// 필수 2 — 아이템 정보 DB (Key: 이름, Value: FItem)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
TMap<FString, FItem> ItemDB;

// 필수 3 — 보유 칭호 (FName 사용)
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Inventory")
TSet<FName> OwnedTitles;

// 함수 — 챕터1-7 UFUNCTION 패턴 적용
UFUNCTION(BlueprintCallable, Category = "Inventory")
void AddItem(FItem Item);

UFUNCTION(BlueprintCallable, Category = "Inventory")
void AcquireTitle(FName Title);

UFUNCTION(BlueprintPure, Category = "Inventory")
bool HasTitle(FName Title) const;

UFUNCTION(BlueprintCallable, Category = "Inventory")
void UseItem(FString ItemName);  // 챕터3-1 ActivateItem 패턴 차용

UFUNCTION(BlueprintCallable, Category = "Inventory")
void PrintBag() const;

STEP 2 — CPP 구현 + BeginPlay 통합 테스트 (필수 1~4)

챕터3-3 TArray 순회·누적 패턴 참고

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void AInvCharacter::BeginPlay()
{
    Super::BeginPlay();

    // 아이템 DB 세팅 (챕터3-3 FItemSpawnRow 구조 참고)
    FItem Sword  = { TEXT("검"),  TEXT("강력한 검"),  TEXT("전사") };
    FItem Potion = { TEXT("물약"), TEXT("체력 회복"), NAME_None   };
    ItemDB.Add(Sword.Name,  Sword);
    ItemDB.Add(Potion.Name, Potion);

    // 필수 1 — TArray 가방에 추가
    AddItem(Sword);
    AddItem(Potion);
    PrintBag();

    // 필수 2 — TMap Key로 아이템 정보 조회
    if (FItem* Info = ItemDB.Find(TEXT("검")))
        UE_LOG(LogTemp, Warning, TEXT("[ItemDB] 검: %s"), *Info->Desc);

    // 필수 3·4 — 칭호 없이 시도 → 실패
    UseItem(TEXT("검"));

    // 칭호 획득 후 재시도 → 성공
    AcquireTitle(TEXT("전사"));
    UseItem(TEXT("검"));

    // 칭호 불필요 아이템 → 성공
    UseItem(TEXT("물약"));
}

UseItem 핵심 로직 (챕터3-1 ActivateItem 패턴):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void AInvCharacter::UseItem(FString ItemName)
{
    FItem* Item = ItemDB.Find(ItemName);
    if (!Item) return;

    // 필수 4 — 칭호 조건 체크
    if (Item->RequiredTitle != NAME_None && !HasTitle(Item->RequiredTitle))
    {
        UE_LOG(LogTemp, Warning, TEXT("[UseItem] %s 불가 — 칭호 '%s' 필요"),
            *ItemName, *Item->RequiredTitle.ToString());
        return;
    }
    UE_LOG(LogTemp, Warning, TEXT("[UseItem] %s 사용 완료"), *ItemName);
}

bool AInvCharacter::HasTitle(FName Title) const
{
    return OwnedTitles.Contains(Title);
}

STEP 3 — WBP_Inventory 위젯 (도전)

챕터4-1 UMG 패턴 그대로 적용

사전 설정 — Build.cs에 UMG 모듈 추가

1
2
3
4
5
// NBC_JangSik_Inv.Build.cs
PublicDependencyModuleNames.AddRange(new string[] {
    "Core", "CoreUObject", "Engine", "InputCore",
    "UMG"  // 챕터4-1 필수 — 없으면 CreateWidget 빌드 에러
});

위젯 생성 — PlayerController BeginPlay (챕터4-1 패턴)

1
2
3
4
5
6
7
8
9
// InvPlayerController.h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI")
TSubclassOf<UUserWidget> InventoryWidgetClass;

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "UI")
UUserWidget* InventoryWidgetInstance;

UFUNCTION(BlueprintPure, Category = "UI")
UUserWidget* GetInventoryWidget() const;
1
2
3
4
5
6
7
// InvPlayerController.cpp — BeginPlay
if (InventoryWidgetClass)
{
    InventoryWidgetInstance = CreateWidget<UUserWidget>(this, InventoryWidgetClass);
    if (InventoryWidgetInstance)
        InventoryWidgetInstance->AddToViewport();
}

위젯 갱신 — SetText 방식 (챕터4-1 UpdateHUD 패턴)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Character에서 아이템 추가/사용 후 호출
void AInvCharacter::UpdateInventoryUI()
{
    APlayerController* PC = Cast<APlayerController>(GetController());
    AInvPlayerController* InvPC = Cast<AInvPlayerController>(PC);
    if (!InvPC) return;

    UUserWidget* Widget = InvPC->GetInventoryWidget();
    if (!Widget) return;

    // 챕터4-1 GetWidgetFromName + SetText 패턴
    if (UTextBlock* BagText = Cast<UTextBlock>(Widget->GetWidgetFromName(TEXT("BagList"))))
    {
        FString BagStr;
        for (const FItem& Item : Bag)
            BagStr += Item.Name + TEXT("\n");
        BagText->SetText(FText::FromString(BagStr));
    }

    if (UTextBlock* TitleText = Cast<UTextBlock>(Widget->GetWidgetFromName(TEXT("TitleList"))))
    {
        FString TitleStr;
        for (const FName& Title : OwnedTitles)
            TitleStr += Title.ToString() + TEXT("\n");
        TitleText->SetText(FText::FromString(TitleStr));
    }
}

WBP_Inventory 위젯 구조

1
2
3
4
WBP_Inventory (Canvas Panel)
├── TextBlock "BagList"   — Bag TArray 아이템 목록
├── TextBlock "TitleList" — OwnedTitles TSet 칭호 목록
└── Button "UseBtn"       → OnClicked → UseItem(선택된 아이템)

버튼 클릭 시 BP에서 GetOwningPlayerPawn() → Cast<AInvCharacter> → UseItem() 호출

  1. GameMode → Default Controller Class를 AInvPlayerController로 설정
  2. WBP_Inventory 생성 (Content Browser → Blueprint → Widget Blueprint) - TextBlock 두 개: 이름 BagList, TitleList - Button 하나: 이름 UseBtn
  3. InvPlayerController BP → InventoryWidgetClass에 WBP_Inventory 할당
  4. UseBtn OnClicked 이벤트: OnClicked → Get Owning Player Pawn → Cast To AMyCharacter → UseItem (ItemName: “검”)
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.