[TPS프로젝트] (5) 인벤토리 기능 개선과 버그 수정

개발자 김선호·2024년 6월 13일
0

TPSProject

목록 보기
5/8
post-thumbnail

기존 인벤토리의 경우에는 아이템 상호작용 구현에만 초점이 맞춰져 있었기 때문에 아이템 종류에 따른 슬롯 위치가 알맞지 않았습니다. 게다가 주무기가 2개 이상 주워진다던가, 다른 종류의 장비로의 스왑이 원활하지 않은 문제가 발생했었습니다. 또한, 루팅 가능한 아이템 목록을 갱신하면서 버튼 오브젝트를 Pool에 반납하는 과정에 문제가 발생하기도 하였습니다.

개선된 인벤토리

아이템 드랍 시 발생된 문제 해결

플레이어가 같은 타입의 장비를 습득했을 때, 자동으로 기존의 아이템을 바닥에 버리는 로직을 작성했습니다. 그러나 플레이어 캐릭터가 아이템 상호작용 범위로부터 벗어나는 판정이 발생하여 같은 아이템에 대한 버튼이 2개 이상 생기거나, 버튼이 반환되면서 딕셔너리에 있는 value가 제거되어 예외가 발생하는 등의 문제가 생겼었습니다.
해당 문제를 해결하기 위해 취한 조치는 다음과 같습니다.

  1. 주무기 오브젝트 전체를 Disable 시키는 것이 아닌 3D 모델만 Disable 시키는 것으로 전환하여 EnterTrigger에 대한 문제를 해결했습니다.
  2. 버튼 오브젝트를 Pool에 반납하는 것이 아닌 보이지 않는 공간에 UI를 배치함으로써 해당하는 오브젝트에 대한 버튼이 유지되도록 변경했습니다.

해당 방법의 경우를 사용하면 Object Pool을 사용하지 않아도 되지 않는가?에 대해 고민해보았는데, 여전히 오브젝트 생성에 대한 비용이 크기 때문에 한번에 100개 200개의 아이템에 대해 상호작용하게 된다면 프리징을 경험할 수 있겠다고 판단, Object Pool은 그대로 유지하였습니다.

아이템 스왑 시 발생된 문제 해결

장비 아이템을 플레이어가 손에서 놓았을 때, 예를들어 주무기를 손에 든 상태에서 보조무기로 전환하는 경우, 주무기 오브젝트 전체를 Disable 시키는 식의 로직을 작성했습니다. 이벤트 트리거를 발생시키는 시점에서 문제가 발생하여 아이템을 드랍하여도 UI가 정상적으로 작동하지 않는 문제가 발생하였습니다.
해당 문제를 해결하기 위해 취한 조치는 다음과 같습니다.

  1. 위 문제와 마찬가지로, 주무기 오브젝트 전체를 Disable 시키는 것이 아닌 3D 모델만 Disable 시키는 것으로 전환하여 EnterTrigger에 대한 문제를 해결했습니다.
  2. 이벤트 트리거를 UI단과 Character단을 분리하고, 로직의 순서가 중요하다고 판단되는 경우에는 이벤트 트리거에 의해 호출되는 것이 아닌 밀접한 게임 오브젝트가 다른 인스턴스의 메소드를 호출하는 식으로 변경하였습니다.

인벤토리 UI 개선

기존 인벤토리의 경우에는 상호작용 기능 구현에만 초점이 맞춰져 있어서 루팅한 아이템이 한 리스트에 포함되는 문제가 있었습니다. 지정한 슬롯에 맞게 아이템 버튼이 들어갈 수 있도록 변경하였으며, 슬롯이 추가되더라도 로직에 큰 변화가 필요 없도록 설계하였습니다.

    // Inspector    
    public GameObject UIHideSpace;              // UI가 숨겨질 공간의 리스트를 할당
    public GameObject LootableContent;          // 루팅 가능한 목록에 대한 Content를 할당
    public GameObject InventoryContent;         // 루팅이 된 인벤토리 목록에 대한 Content를 할당
    public GameObject PrimaryWeaponContent;     // 주무기 Content를 할당
    public GameObject SecondaryWeaponContent;   // 보조무기 Content를 할당 
    //추가적인 슬롯의 경우 위 Inspector에 추가하고 "InitUIType" 메소드에 Key를 추가할 것

    public GameObject UIPrefab; // 생성할 UI 프리팹을 할당(버튼)
    public Dictionary<EItemType, GameObject> ContentDictionary = new Dictionary<EItemType, GameObject>(); // 콘텐츠UI에 아이템 타입을 할당하여 자동으로 부모가 설정되도록 하는 딕셔너리

버튼의 부모가 될 Object들을 레퍼런싱 할 수 있도록 Inspector에 추가하고, InitUIType 메소드에 딕셔너리 키를 추가하면 "OnUIPickedUpItem" 메소드에 의해 자동으로 할당된 오브젝트를 부모로 설정합니다.


    // 버튼을 타입에 맞는 리스트로 이동시키는 메소드
    void OnUIPickedUpItem(object parameter)
    {
        TGItem ptrItem = (TGItem)parameter;
        TGUILootableItemInterective ptrUI = lootableItemUIDictionary[ptrItem];

        ptrUI.transform.SetParent(ContentDictionary[ptrItem.itemType].transform);
    }

해당 메소드는 EventTrigger에 의해 실행됩니다.

마이너한 변경점

아이템에 대한 물리 효과를 삭제하고 바닥에 아이템이 드랍되도록 변경하였습니다.

결과물

인벤토리UI 소스코드
https://github.com/devsensational/3DGameProject/blob/main/3DProject/Assets/Scripts/Game/GameUI/InGameUI/TGUIInventory.cs

인벤토리 UI 버튼 소스코드
https://github.com/devsensational/3DGameProject/blob/main/3DProject/Assets/Scripts/Game/GameUI/InGameUI/TGUILootableItemInterective.cs

게임 아이템 소스코드
https://github.com/devsensational/3DGameProject/blob/main/3DProject/Assets/Scripts/Game/Item/TGItem.cs

캐릭터 소스코드
https://github.com/devsensational/3DGameProject/blob/main/3DProject/Assets/Scripts/Game/Unit/TGCharacter.cs

아래는 개선된 인벤토리 시연 영상입니다.

profile
프로젝트 진행 과정을 주로 업로드합니다

0개의 댓글