반응형
이번 글에서는 마지막으로 인벤토리의 드래그 드롭 기능을 구현해 보도록 하겠습니다
반응형
일단 저번에 작성했던 스크립트 일부를 수정했습니다
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
private Dictionary<ItemDataSO, int> itemContainer = new();
public static Inventory Instance { get; private set; }
public event Action<ItemDataSO, int> OnItemChanged;
public event Action<ItemDataSO> OnNewItemAdded;
private void Awake()
{
Instance = this;
}
public void AddItem(Item item)
{
if (itemContainer.ContainsKey(item.itemData))
{
if(item.itemData.MaxStackCount > itemContainer[item.itemData])
{
itemContainer[item.itemData]++;
OnItemChanged?.Invoke(item.itemData, itemContainer[item.itemData]);
Destroy(item.gameObject);
}
}
else
{
itemContainer.Add(item.itemData, 1);
OnNewItemAdded?.Invoke(item.itemData);
Destroy(item.gameObject);
}
}
public void RemoveItem(ItemDataSO item, Vector2 pos)
{
if(itemContainer.ContainsKey(item))
{
Instantiate(item.ItemPrefab, pos, Quaternion.identity);
itemContainer[item]--;
//이벤트 실행
OnItemChanged?.Invoke(item, itemContainer[item]);
if (itemContainer[item] <= 0)
{
itemContainer.Remove(item);
}
}
}
public int GetItemCount(ItemDataSO data)
{
if (itemContainer.TryGetValue(data, out var count))
{
//있다면 카운트를 반환
return count;
}
//아이템이 없다면 -1반환
return -1;
}
private void OnDestroy()
{
Instance = null;
}
}
using System;
using UnityEngine;
using UnityEngine.UI;
public class InventoryViewer : MonoBehaviour
{
[SerializeField] private Slot slotPrefab;
[SerializeField] private Transform slotParent;
[SerializeField] private Image changeSlotUI;
private bool isChanging;
private Slot currentChangeSlot;
//현제 포인터가 가리키고있는 슬롯
private Slot pointerUpSlot;
private void Start()
{
//이벤트 구독
Inventory.Instance.OnNewItemAdded += HandleItemAdded;
}
private void HandleItemAdded(ItemDataSO obj)
{
Instantiate(slotPrefab, slotParent).Init(obj);
}
//Slot설정
public void SetPointerSlot(Slot slot)
{
pointerUpSlot = slot;
}
private void Update()
{
if (Input.GetMouseButtonUp(1) && isChanging)
{
if(pointerUpSlot != null)
{
SwapSlot(pointerUpSlot);
}
changeSlotUI.gameObject.SetActive(false);
currentChangeSlot = null;
isChanging = false;
}
if (isChanging)
{
changeSlotUI.transform.position = Input.mousePosition;
}
}
public void StartChange(Slot slot)
{
isChanging = true;
changeSlotUI.gameObject.SetActive(true);
changeSlotUI.sprite = slot.currentSaveItem.ItemSprite;
currentChangeSlot = slot;
}
public void SwapSlot(Slot slot)
{
//같은 슬롯끼리 바꾸려고 한다면 못하도록
if (slot == currentChangeSlot) return;
//두 아이템을 바꿔주기
var oldData = slot.currentSaveItem;
slot.Init(currentChangeSlot.currentSaveItem);
currentChangeSlot.Init(oldData);
currentChangeSlot = null;
}
}
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class Slot : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler, IPointerExitHandler
{
private TMP_Text itemCountText;
private Image itemImage;
private InventoryViewer inventoryViewer;
public ItemDataSO currentSaveItem { get; private set; }
private void Awake()
{
itemCountText = GetComponentInChildren<TMP_Text>();
itemImage = transform.Find("ItemImage").GetComponent<Image>();
inventoryViewer = FindObjectOfType<InventoryViewer>();
}
public void Init(ItemDataSO item)
{
currentSaveItem = item;
itemCountText.text = Inventory.Instance.GetItemCount(item).ToString();
itemImage.sprite = item.ItemSprite;
Inventory.Instance.OnItemChanged += HandleItemAdded;
}
private void HandleItemAdded(ItemDataSO item, int count)
{
if(currentSaveItem == item)
{
if(count == 0)
{
Destroy(gameObject);
}
else
{
itemCountText.text = count.ToString();
}
}
}
private void OnDestroy()
{
if(Inventory.Instance != null)
{
Inventory.Instance.OnItemChanged -= HandleItemAdded;
}
}
public void OnPointerDown(PointerEventData eventData)
{
if(eventData.button == PointerEventData.InputButton.Left)
{
Inventory.Instance.RemoveItem(currentSaveItem, Random.insideUnitCircle);
}
else if(eventData.button == PointerEventData.InputButton.Right)
{
inventoryViewer.StartChange(this);
}
}
//포인터가 가리키는 슬롯 설정
public void OnPointerEnter(PointerEventData eventData)
{
inventoryViewer.SetPointerSlot(this);
}
public void OnPointerExit(PointerEventData eventData)
{
inventoryViewer.SetPointerSlot(null);
}
}
새로운 스크립트를 작성할 필요도 없이 구현됩니다
그다음으로는 UI 구현입니다
빈 이미지를 하나 추가해 주고 RayCastTarget을 꺼주고 비활성 상태로 만들어 주세요
그다음으로 만든 이미지를 InventoryViewer에 할당해 주세요
그럼 끝났습니다! 잘 작동하는 것을 확인할 수 있습니다
저는 슬롯끼리 바뀌는 것까지만 구현했습니다
이제 이 코드를 응용하여 더 다양한 기능이 있는 인벤토리를 구현할 수 있을 것입니다
인벤토리 코드는 패키지로 만들어 첨부해 놓았습니다
인벤토리 관련 글은 여기까지 하도록 하겠습니다
반응형
'유니티 > 인벤토리' 카테고리의 다른 글
[Unity] 인벤토리 - 2. UI와 아이템 버리기 (0) | 2024.02.08 |
---|---|
[Unity] 인벤토리 - 1. 기본 구현 (0) | 2024.02.08 |