✅ 기능
이전 글에서 런타임 도중 씬 내에 배치되어있는 아이템을 바라보고, 획득하는 과정까지 구현을 해보았습니다. 이번 글에서는 인벤토리에 들어온 아이템들에 대한 슬롯에 대해 아이템을 이동하고, 합치고, 반으로 나누거나 퀵슬롯에 등록하는 등 아이템 슬롯을 관리하는 기능에 대해 구현하고 이를 정리해봤습니다.
🔨 로드맵
2. 유니티 인벤토리 시스템(2) - 아이템(ScriptableObject)
3. 유니티 인벤토리 시스템(3) - 아이템 슬롯(인벤토리 슬롯)
[📌현재 글] 5. 유니티 인벤토리 시스템(5) - 아이템 슬롯 관리
✅ 구현
1. DragSlot
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 아이템을 드래그 할 경우 임시로 DragSlot에 아이템을 저장한다.
/// </summary>
public class DragSlot : Singleton<DragSlot>
{
[HideInInspector] public InventorySlot CurrentSlot;
[HideInInspector] public bool IsShiftMode;
[SerializeField] private Image mItemImage;
public void DragSetImage(Image _itemImage)
{
mItemImage.sprite = _itemImage.sprite;
SetColor(1);
}
public void SetColor(float alpha)
{
Color color = mItemImage.color;
color.a = alpha;
mItemImage.color = color;
}
}
- 아이템을 옮기거나, 서로 위치를 바꿀 때 임시로 드래그한 아이템을 저장하기위해 사용하는 클래스입니다.
[HideInInspector] public InventorySlot CurrentSlot;
- 드래그를 시작할경우 드래그를 시작한 슬롯에 있는 아이템슬롯 대한 데이터를 가져오고 저장합니다.
[HideInInspector] public bool IsShiftMode;
- 드래그를 할 때 쉬프트를 사용했는지 확인합니다.
- 아이템을 가지고있는 개수의 반개만큼 옮기기 위해 사용합니다.
[SerializeField] private Image mItemImage;
public void DragSetImage(Image _itemImage)
- 현재 드래그한 아이템에 대한 이미지를 저장하고 설정하기 위한 변수와 함수입니다.
2. 드래그 오버라이드
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 인벤토리 슬롯 하나를 담당
/// </summary>
public class InventorySlot : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IPointerEnterHandler, IPointerExitHandler
{
...
// 마우스 드래그 시작 오버라이드
public void OnBeginDrag(PointerEventData eventData)
{
if (mItem != null)
{
//쉬프트 (반으로 나누기 모드 활성화)
if (Input.GetKey(KeyCode.LeftShift)) { DragSlot.Instance.IsShiftMode = true; }
else { DragSlot.Instance.IsShiftMode = false; }
//현재 슬롯으로 등록
DragSlot.Instance.CurrentSlot = this;
DragSlot.Instance.DragSetImage(mItemImage);
DragSlot.Instance.transform.position = eventData.position;
}
}
// 마우스 드래그 중 매 프레임마다 호출되는 오버라이드
public void OnDrag(PointerEventData eventData)
{
if (mItem != null)
DragSlot.Instance.transform.position = eventData.position;
}
// 마우스 드래그 종료 오버라이드
public void OnEndDrag(PointerEventData eventData)
{
DragSlot.Instance.SetColor(0);
DragSlot.Instance.CurrentSlot = null;
}
// 해당 슬롯에 무언가가 마우스 드롭 됐을 때 발생하는 이벤트
public void OnDrop(PointerEventData eventData)
{
//쉬프트 모드인 상황에서 해당 위치에 아이템이 있는경우, 반으로 나눌 수 없기에 리턴한다.
if (DragSlot.Instance.IsShiftMode && mItem != null) { return; }
//드래그 슬롯에 놓여진 아이템과, 바꿔질 아이템의 마스크가 모두 통과되면 바꾼다.
if (!IsMask(DragSlot.Instance.CurrentSlot.Item)) { return; }
//타겟 드래그 슬롯에 이미 아이템이 있는경우, 해당 아이템이 직전의 아이템 슬롯에서 마스크를 체크한다.
if (mItem != null && !DragSlot.Instance.CurrentSlot.IsMask(mItem)) { return; }
ChangeSlot();
//mItemActionManager.SlotOnDropEvent(this); 드롭 이벤트 호출
}
}
- InventorySlot.cs에서 마우스 오버라이드를 추가하고, 각 이벤트에 맞게 스크립트를 작성합니다.
public class InventorySlot : MonoBehaviour,
IPointerClickHandler, IBeginDragHandler, IDragHandler,
IEndDragHandler, IDropHandler, IPointerEnterHandler, IPointerExitHandler {}
- 유니티에서 제공하는 EventSystem의 기능을 의도에 맞게 새롭개 오버라이드 합니다.
public void OnBeginDrag(PointerEventData eventData)
- 마우스 위치의 아이템 슬롯에 아이템이 있는 상태에서 드래그를 시작하면(클릭 후 움직임) 실행되는 함수입니다.
- 이 상태에서 LeftShift를 누른 상태라면 IsShiftMode가 참이되며, 올바른 슬롯에 아이템을 놓을 때 반개만 아이템이 이동됩니다.
- DragSlot에 현재 슬롯의 아이템을 등록하고 이미지를 변경시킵니다.
public void OnDrag(PointerEventData eventData)
- 드래그를 한 상태에서 마우스를 움직이면 호출되는 함수입니다.
- DragSlot에 있는 아이템의 Image(Sprite)가 마우스 포인터를 따라다니며 드래그를 하는 연출을 보여주도록 합니다.
public void OnEndDrag(PointerEventData eventData)
- 드래그가 끝나는 순간에(클릭을 놓는 순간) 호출되는 함수입니다.
- 드래그가 종료되었으니 DragSlot에 있는 아이템을 제거하고, Image(Sprite)도 제거합니다.
public void OnDrop(PointerEventData eventData)
- OnEndDrag와 같이 클릭을 놓는 순간에 호출되며, InventorySlot이 있는 컴포넌트의 UI에 마우스 포인터가 있을경우 해당 컴포넌트에서 호출됩니다.
- 외부의 다른 InventorySlot에서 호출될 수 있다는 의미입니다.
- 포인터에 있는 해당 InventorySlot에 DragSlot의 데이터를 가지고 처리를 합니다.
3. 아이템 바꾸기
...
public class InventorySlot : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IPointerEnterHandler, IPointerExitHandler
{
...
private void ChangeSlot()
{
if(DragSlot.Instance.CurrentSlot.Item.Type >= ItemType.Etc)
{
//쉬프트 모드 관계 없이 일어날 수 있는 경우
//새로운 슬롯과 이전 슬롯의 아이템ID가 같은경우 개수를 합친다.
if (mItem != null && mItem.ItemID == DragSlot.Instance.CurrentSlot.Item.ItemID)
{
int changedSlotCount;
if (DragSlot.Instance.IsShiftMode) { changedSlotCount = (int)(DragSlot.Instance.CurrentSlot.mItemCount * 0.5f); }
else { changedSlotCount = DragSlot.Instance.CurrentSlot.mItemCount; }
UpdateSlotCount(changedSlotCount);
DragSlot.Instance.CurrentSlot.UpdateSlotCount(-changedSlotCount);
return;
}
//쉬프트 모드인경우 개수를 반으로 나눈다.
if (DragSlot.Instance.IsShiftMode)
{
//changedSlotCount 개수만큼 더하고 뺄것이다 (+와 -의 차이가 0이어야 아이템이 복사, 유실되지 않는다.)
int changedSlotCount = (int)(DragSlot.Instance.CurrentSlot.mItemCount * 0.5f);
//(int)로의 형변환으로 인해 0이 되는 경우는 (int)(1 * 0.5f)이기에 단순히 새로운 슬롯으로 옮긴다.
if (changedSlotCount == 0)
{
AddItem(DragSlot.Instance.CurrentSlot.Item, 1);
DragSlot.Instance.CurrentSlot.ClearSlot();
return;
}
//위 모든 경우가 아닌경우 새로운 슬롯에 새로운 아이템을 생성한다.
AddItem(DragSlot.Instance.CurrentSlot.Item, changedSlotCount);
DragSlot.Instance.CurrentSlot.UpdateSlotCount(-changedSlotCount);
return;
}
}
//슬롯 서로 교환하기
Item tempItem = mItem;
int tempItemCount = mItemCount;
AddItem(DragSlot.Instance.CurrentSlot.mItem, DragSlot.Instance.CurrentSlot.mItemCount);
if (tempItem != null) { DragSlot.Instance.CurrentSlot.AddItem(tempItem, tempItemCount); }
else { DragSlot.Instance.CurrentSlot.ClearSlot(); }
}
...
}
- InventorySlot.cs에 함수를 추가하여 드래그가 올바르게 이뤄진경우, 해당 함수를 호출하여 두개의 슬롯을 서로 바꾸도록 합니다.
if(DragSlot.Instance.CurrentSlot.Item.Type >= ItemType.Etc)
- 현재 변경하려는 아이템이 Etc 이상(장비, NONE, SKILL)이 아닌경우, 중첩이 가능할 수 있기때문에 내부로 진입합니다.
if (mItem != null && mItem.ItemID == DragSlot.Instance.CurrentSlot.Item.ItemID)
- 현재 아이템과 드래그슬롯의 아이템이 동일한경우 개수만 변경하도록 합니다.
if (DragSlot.Instance.IsShiftMode)
- 동일하지 않은 상태에서 쉬프트모드인경우에 호출됩니다.
✅ 사용(적용) 예시
- Canvas 내에 InventorySlot을 하나 만듭니다.
- DragSlot 컴포넌트를 추가하여 드래그 이벤트에 대해 전용으로 기능을 수행하도록 합니다.
- CanvasGroup을 사용하여 마우스 이벤트를 무시하도록 설정합니다.
- InventorySlot.cs가 있지만 Mask기능을 수행하지 않습니다.
'unity game modules' 카테고리의 다른 글
[유니티] 인벤토리 시스템(번외) - 쿨타임 기능 (0) | 2022.12.28 |
---|---|
[유니티] 인벤토리 시스템(6) - 아이템 사용 (0) | 2022.12.27 |
[유니티] 인벤토리 시스템(4) - 아이템 획득 (0) | 2022.12.26 |
[유니티] 인벤토리 시스템(3) - 아이템 슬롯(인벤토리 슬롯) (0) | 2022.12.26 |
[유니티] 인벤토리 시스템(2) - 아이템(ScriptableObject) (0) | 2022.12.26 |