인터페이스
란 어떤 메서드를 구현하도록 강제하는 계약
인터페이스를 상속하는 클래스는 해당 인터페이스의 메서드를 반드시 구현해야 한다.
인터페이스는 메서드는 형태만 결정하고 메서드의 구현 방법은 자신을 상속하는 클래스에 맡긴다.
내부 구현은 클래스마다 달라도 상관없다.
유니티에서 지원하는 이벤트 IPointer
IPpointerInterface
는 유니티 EventSystems에서 기본으로 제공하는 인터페이스이며, 터치 이벤트를 구현할 때 자주 사용된다.
만약 IPointer가 작동하지 않는다면?
1. Canvas에 Graphic Raycaster 컴포넌트가 추가되어 있는지 확인
2. EventSystem에서 제공하는 기능이기 때문에 씬에 EventSystem이 있는지 확인
3. UI오브젝트에 Raycast Target이 체크되어 있는지 확인
인벤토리 슬롯 UI를 관리하는 클래스가 IPointerDownHandler 인터페이스를 상속 받도록 한다
인벤토리창에서 슬롯을 선택하면 OnPointerDown()이 호출된다
using UnityEngine.EventSystems;
public class UI_ItemSlot : MonoBehaviour, IPointerDownHandler
{
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("Equiped new item + " + item.data.itemName);
}
}
eventData
: PointerEventData는 마우스 클릭 또는 터치와 같은 포인터 이벤트와 관련된 데이터를 포함한 객체
eventData를 통해 클릭된 위치, 클릭된 버튼 등의 정보에 접근할 수 있다.
Equipment 타입 아이템을 관리하는 필드 생성
public List<InventoryItem> equipment; //착용 가능한 아이템만 저장하는 리스트
public Dictionary<ItemData, InventoryItem> equipmentDictionary;
private void Start()
{
equipment = new List<InventoryItem>();
equipmentDictionary = new Dictionary<ItemData, InventoryItem>();
}
public void EquipItem(ItemData _item)
{
InventoryItem newItem = new InventoryItem(_item);
equipment.Add(newItem);
equipmentDictionary.Add(_item, newItem);
}
인벤토리 슬롯을 클릭했을 때, 착용 가능한 장비이면 Inventory의 EquipItem()을 호출하여 착용할 아이템 데이터를 전달
public void OnPointerDown(PointerEventData eventData)
{
//아이템 타입에 따라 처리 방법을 달리한다
if (item.data.itemType == ItemType.Equipment)
Inventory.instance.EquipItem(item.data);
}
[문제점]
public Dictionary<ItemData_Equipment, InventoryItem> equipmentDictionary; //ItemData_Equipment는 ItemData를 상속한다
//장비 유형에 관한 정보 사용하기 위해 ItemData_Equiment를 key로 갖는다
해당 장비 아이템을 착용하고 있는지 확인하기 위해 딕셔너리 순회
만약 이전에 착용 중인 아이템이 있다면 해당 아이템을 제거하고 인벤토리에 추가
//아이템을 착용
public void EquipItem(ItemData _item)
{
ItemData_Equipment newEquipment = _item as ItemData_Equipment;
InventoryItem newItem = new InventoryItem(newEquipment);
//아이템을 제거할 변수 선언
ItemData_Equipment itemToRemove = null;
//해당 유형의 장비를 이미 착용하고 있는지 장비 딕셔너리를 순회하며 확인
foreach (KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictionary)
{
//장비 타입이 같은지 확인
if (item.Key.equipmentType == newEquipment.equipmentType)
itemToRemove = item.Key; //같다면 아이템을 제거할 변수에 할당
}
//삭제할 아이템이 있다 = 같은 유형의 장비를 이미 착용하고 있다
//현재 착용 중인 장비를 삭제 처리한다
if (itemToRemove != null)
UnequipItem(itemToRemove);
//메서드가 호출되면 전달받은 아이템을 장비 리스트와 장비 딕셔너리에 추가
equipment.Add(newItem);
equipmentDictionary.Add(newEquipment, newItem);
}
private void UnequipItem(ItemData_Equipment itemToRemove)
{
if (equipmentDictionary.TryGetValue(itemToRemove, out InventoryItem value))
{
equipment.Remove(value);
equipmentDictionary.Remove(itemToRemove);
//인벤토리 창에서 장비한 아이템 제거
RemoveItem(_item);
}
}
public void EquipItem(ItemData _item)
{
//현재 착용 중인 장비를 삭제 처리한다
if (oldEquipment != null)
{
UnequipItem(oldEquipment);
//착용했던 장비를 다시 인벤토리에 추가한다
AddItem(oldEquipment);
}
equipment.Add(newItem);
equipmentDictionary.Add(newEquipment, newItem);
//인벤토리 창에서 장비한 아이템 제거
RemoveItem(_item);
}
public void CleanUpSlot()
{
//아이템 슬롯 아이콘을 비운다
item = null;
itemImage.sprite = null;
itemImage.color = Color.clear;
itemText.text = "";
}
Inventory 클래스에 슬롯 UI 업데이트 시 슬롯을 비우는 메서드 호출
public void EquipItem(ItemData _item)
{
//아이템 슬롯 업데이트
UpdateSlotUI();
}
private void UpdatSlotUI()
{
//슬롯UI를 업데이트 하기 전에 슬롯을 한번 비워준다
for(int i = 0; i < inventoryItemSlot.Length; i++)
{
inventoryItemSlot[i].CleanUpSlot();
}
for(int i = 0; i < stashItemSlot.Length; i++)
{
stashItemSlot[i].CleanUpSlot();
}
}
public class UI_EquipmentSlot : UI_ItemSlot
{
public EquipmentType slotType;
}
[SerializeField] private Transform equipmentSlotParent;
private UI_EquipmentSlot[] equipmentSlot;
private void UpdateSlotUI()
{
//장비 슬롯 배열의 각각의 아이템 확인
for(int i = 0; i < equipmentSlot.Length; i++)
{
//장비 딕셔너리에 있는 각각의 물품을 비교
foreach(KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictionary)
{
//슬롯 타입과 같은 타입의 장비 아이템으로 장비 슬롯 업데이트
if(item.Key.equipmentType == equipmentSlot[i].slotType)
equipmentSlot[i].UpdateSlot(item.Value);
}
}
}