유니티 RPG - 22. 인벤토리 시스템 요약 정리
Intro
이번 포스팅에서는 여태 만든 인벤토리 시스템의 구조부터, 동작하는 방식과 각 스크립트들에 대해 정리해보았습니다.
먼저 인벤토리 시스템에 필요한 아이템의 상속구조와 인벤토리의 UI를 책임질 클래스들에 대해 정리해보았습니다.
/*
<아이템 구조>
* Item : 인벤토리안의 각 아이템슬롯에 들어가는 실제 아이템. 데이터를 받아 세팅 및 각 아이템에 필요한 내부적인 기능들을 담당.
** CountableItem : 갯수가 있는 아이템
- AddAmountAndGetExcess(int amount) - 동일한 아이템이 추가될 때, 추가될 아이템의 갯수와 현재 가지고있는 아이템 갯수를 합하여 한 슬롯이 가질수 있는 최대량보다 많으면 초과량 반환.
- SetAmount(int amount) - 한 아이템슬롯에 들어갈수있는 아이템의 갯수 범위를 제한.
*** PortionItem : 포션 아이템(소모성)
- IUsableItem 인터페이스를 상속받아 아이템의 사용을 구현
- Use() : 아이템 사용 함수(현재는 갯수 -1 차감)
** EquipmentItem : 장비 아이템(현재는 아무런 기능이 없음)
* WeaponItem : 무기 아이템
* ItemData : 아이템들이 공통적으로 가지는 데이터를 보관.
- CreateItem() : 실제 아이템 객체를 생성(추상클래스)하는 함수 -> 개별 아이템데이터에서 구현
** CountableItemData : 갯수가 있는 아이템 데이터
- maxAmount : 갯수가 있는 아이템의 최대갯수(한 슬롯당)
*** PortionItemData : 포션 아이템 데이터
- PortionItemDTO(포션 아이템 직렬화 전용 클래스)의 데이터를 받아 초기화.
- CreateItem() 의 실제 구현 -> 초기화된 데이터를 가지는 포션 아이템 객체를 생성
** EquipmentItemData : 장비 아이템 데이터
*** WeaponItemData : 무기 아이템 데이터
- WeaponItemDTO(무기 아이템 직렬화 전용 클래스)의 데이터를 받아 초기화.
- CreateItem() 의 실제 구현 -> 초기화된 데이터를 가지는 무기 아이템 객체를 생성
DTO 클래스 : WeaponItemDTO 와 PortionItemDTO 가 있으며, JSON 파일로의 데이터 직렬화를 위한 클래스
*/
Inventory
Inventory 클래스는 인벤토리내의 아이템들을 관리하며, 인벤토리의 실질적인 동작들을 담당하는 클래스입니다.
/*
<Inventory>
* items[] 배열은 인벤토리에 존재하는 36칸의 아이템을 저장하는 배열입니다.
- 특정 슬롯의 아이템 데이터는 index를 통해 접근이 가능하며, Getter 메서드를 통해 데이터를 가져올 수 있습니다.
* 인벤토리는 키보드 'I' 키 입력을 통해 활성 및 비활성화 할 수 있습니다.
[인벤토리에 아이템 추가]
- 인벤토리에 아이템을 추가하는 작업은 AddItem 함수에서 진행됩니다.
- 추가하려는 아이템이 CountableItem 일 때는 먼저 인벤토리에 이미 동일한 아이템이 있는지 조사합니다.
- 동일한 아이템이 있을 때 : 새로 추가할 아이템과 갯수를 합칠 여유가있는지 확인한 뒤 인벤토리에 아이템을 추가합니다.
- 동일한 아이템이 없을 때 : 빈 슬롯을 찾아 아이템을 추가합니다.
[인벤토리의 아이템 제거]
- 인벤토리의 아이템을 제거하는 작업은 Remove 함수에서 진행됩니다.
- 아이템 제거를 위해 items 배열의 해당 인덱스 아이템을 비워줍니다.
- items[index] = null
- 아이콘 및 수량 텍스트 제거를 위해 InventoryUI의 RemoveItem 함수를 호출합니다.
[슬롯간 아이템 스왑]
- 두 슬롯간의 아이템 스왑은 Swap 함수에서 진행됩니다.
- 갯수가 있는 아이템의 경우
- 두 아이템이 같을 때 : A -> B로 스왑하면, B슬롯에 합쳐집니다. 합쳐지고 남은 수량은 A슬롯에 남습니다.
- 두 아이템이 다를 때 : 두 아이템의 위치만 변경됩니다.
- 일반적인 아이템의 경우
- 두 아이템의 위치만 변경됩니다.
[아이템 사용]
- 아이템의 사용은 Use 함수에서 진행됩니다.
- 만약 아이템이 IUsableItem 인터페이스를 상속한 아이템이라면
- 해당 아이템의 Use(IUsableItem로 구현한 함수) 함수를 호출하여 갯수를 차감시킵니다.
[슬롯 갱신]
- 아이템의 추가, 스왑, 사용 후에는 해당 슬롯의 상태를 업데이트하는 함수 UpdateSlot 이 호출됩니다.
- UpdateSlot 함수 호출을 통해 해당 슬롯의 아이콘 및 수량 텍스트가 업데이트 됩니다.
*/
InventoryUI
InventoryUI 클래스는 인벤토리 GUI를 그리며, Inventory 클래스와 ItemSlotUI 클래스 사이에서 통신하고
인벤토리내의 각종 마우스 이벤트들을 처리합니다.
/*
<InventoryUI>
* slotUIList : 인벤토리의 각 슬롯 정보를 리스트 형태로 관리합니다.
- Inventory 에서 특정 슬롯에 대한 접근을 요청하면 slotUIList를 통해 슬롯에 접근합니다.
[슬롯 생성]
- InitSlot 함수에서 미리 만들어둔 슬롯 프리팹을 위치,크기 등을 조절하여 총 36개의 슬롯을 생성합니다.
[마우스 이벤트]
- 마우스 이벤트는 포인터 인터페이스를 사용하지 않고, GraphicRayCaster를 이용하여 구현하였습니다.
- 인벤토리내 마우스 이벤트는 슬롯을 클릭, 드래그앤드롭 하는것과 슬롯에 마우스를 갖다댈 때 강조효과를 보여주는 이벤트가 있습니다.
- RaycastAndgetFirstComponent 함수를 통해 마우스 커서위치에 레이캐스팅된 UI 정보를 가져와서 사용했습니다.
- OnPointerDown() : 마우스를 눌렀을 때 이벤트를 처리합니다.
- 좌클릭과 우클릭으로 나누어 처리하였습니다.
- 좌클릭 : 클릭한 슬롯 정보를 가져옵니다.
- 클릭된 곳의 위치를 저장합니다.
- 클릭된 슬롯 UI를 가장 위로 표시합니다.
- 우클릭 : 클릭한 슬롯의 아이템을 사용합니다.
- OnPointerEnterAndExit() : 마우스 커서가 슬롯에 올라갈때와 나갈때 이벤트처리
- 슬롯위로 마우스커서가 올라갈때 강조효과가 나타납니다.
- OnPointerDrag() : 마우스 드래그중일 때 이벤트를 처리합니다.
- 슬롯을 좌클릭하여 드래그하는 상태라면 아이콘이 마우스커서를 따라 움직이도록 하였습니다.
- OnPointerUp() : 마우스를 뗐을 때 이벤트를 처리합니다.
- 좌클릭시 저장해둔 위치정보를 복원합니다.
- 만약 마우스를 뗀곳이 특수한 위치라면 EndDrag() 호출을 통해 추가적인 이벤트를 처리합니다.
- EndDrag() : 마우스를 뗐을 때 발생하는 이벤트(아이템 스왑, 이동, 버리기)를 처리합니다.
- 아이템이 있는 슬롯위에서 드래그를 종료했을 때는 아이템 스왑 및 이동
- 인벤토리 UI 바깥에서 드래그를 종료했을 때는 아이템 버리기를 처리합니다.
[슬롯관련 처리]
- Inventory 클래스에서 슬롯에 대한 처리(아이콘 및 텍스트 등록/제거)요청이 있다면 index를 통해 슬롯에 접근합니다.
*/
ItemSlotUI
ItemSlotUI 클래스는 InventoryUI 클래스와 통신하며
각 아이템 슬롯에서 보여질 아이템의 갯수 및 아이콘의 설정과
마우스 커서가 슬롯을 지날 때, 그 슬롯의 강조효과를 보여줍니다.
/*
<ItemSlotUI>
- ItemSlotUI 에서는 슬롯의 아이콘, 갯수텍스트, 강조효과, 활성/비활성화 슬롯의 색상 등을 설정합니다.
[강조효과]
- 슬롯의 강조효과(하이라이트)는 코루틴으로 작성하였습니다.
- 강조효과는 하이라이트 이미지의 Alpha 값을 정해둔 Duration 동안에 증가 및 감소시킴으로 구현하였습니다.
[아이콘등록 및 수량 텍스트 설정]
- 인벤토리에 아이템이 추가될 때 SetItemIconAndAmount 함수를 통해 아이콘 및 텍스트가 설정됩니다.
- 아이콘은 JSON 파일에 저장되어있는 아이콘 이름을 받아와서, 어드레서블에 등록되어있는 아이콘 에셋을
가져와 붙이는 식으로 구현했습니다.
- ResourceManager 클래스의 LoadIcon 함수를 호출하여 어드레서블 에셋을 가져옵니다.
- 아이콘 등록이 상대적으로 느린이유로 텍스트 설정과 함께 묶어 실행되도록했습니다.
*/
댓글남기기