1. 실전 인벤토리 만들어 보기
인벤토리 제작은 유니티 6.1을 사용했습니다.
추가로 DOTween을 설치해 주셔야 합니다(무료 버전)
우선 인벤토리의 모양은 아래 이미지와 같습니다.
UI 이미지들의 모양이 조금 볼품이 없어도 기능적인 부분만 봐주시면 됩니다.
인벤토리의 작동 방식은 Tab A라는 큰 묶음 안에 Slot을 배치해서 사용하며 이런 Tab의 묶음은
필요한 만큼 추가할 수 있습니다.
획득한 아이템을 클릭하여 판매할수 있는 기능과 해당 아이템을 드래그해서 다른 Tab으로 배치할 수
있는 기능이 포함됩니다.
위 이미지와 같이 Inventory 메인에 Content A 안에 Slot 묶음과 Content B 역시 같은 구조이며
이런 Content A, B의 전환을 도와주는 Tab Group으로 구성되어 있습니다
첫 번째 작업으로 Content A의 구조를 살펴보겠습니다.
Rect Transform의 위치는 만드시는 인벤토리의 크기에 맞게 잡아 주시면 되며
Grid Layout Group을 추가하여 Content 안에 들어오는 Slot들의 배열을 지정해 줍니다.
Slot의 구조입니다
역시 Grid Layout Group이 추가되어 있는데 이건 아이템이 들어왔을 때 Slot 중앙에 위치하기 위해 필요합니다.
Middle Center 꼭 지정해 주시고 나머지 InventorySlot.cs 스크립트를 추가해 줍니다.
using UnityEngine;
using UnityEngine.EventSystems;
public class InventorySlot : MonoBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
var newItem = eventData.pointerDrag.GetComponent<InventoryItem>();
if (transform.childCount == 0)
{
// Drop 되는 곳의 Slot이 비어 있다면 해당자리에 넣어 준다.
newItem.parentAfterDrag = transform;
}
else
{
// Drop 되는 곳의 Slot에 아이템이 들어 있다면 기존 아이템과 위치를 교환한다.
var orgItem = transform.GetComponentInChildren<InventoryItem>();
orgItem.parentAfterDrag = newItem.parentAfterDrag;
orgItem.transform.SetParent(orgItem.parentAfterDrag);
newItem.parentAfterDrag = transform;
}
}
}
IDropHandler 인터페이스가 추가되어 있습니다.
OnDrop의 기능은 아래 코드(InventoryItem.cs)에 나오지만 Drag를 끝내고 아이템을 놓는다면 OnEndDrag 이벤트가
발생합니다. 그런데 아이템이 들어갈 자리에 OnDrop 이벤트가 있다면 OnDrop의 기능을 수행 후 OnEndDrag 기능이
마무리하는 역할을 하게 되는 겁니다.
아주 중요한 부분이니 조금 복잡해도 잘 이해하셔야 하는 부분입니다.
한번 더 정리하면
OnEndDrag 진입 -> OnDrop 이 있다면 먼저 실행 후 -> OnEndDrag가 마무리
드롭될 아이템의 정보를 받아 옵니다.
드롭되는 슬롯에 아이템이 없다면 드롭되는 Slot의 위치 정보를 아이템 parentAfterDrag에 넘겨줍니다.
만약 드롭되는 곳에 아이템이 있다면 orgItem에 해당 슬롯의 자식으로 있는 아이템을 받아 옵니다.
그런 후 드롭될 아이템의 원래 슬롯 위치를 orgItem의 위치로 변경해 준 후
orgItem의 SetParent를 이용해 변경된 Slot으로 옮겨 줍니다.
** newItem의 parentAfterDrag의 위치정보는 아래 InventoryItem.cs에서 Darg를 시작하기 전
아이템이 들어 있던 Slot의 위치 정보를 가지고 있습니다 **
마지막으로 newItem.parentAfterDrag = transform; 드롭될 아이템의 위치를 현 슬롯의 위치로 변경합니다.
자 여기서 한 가지 짚고 넘어갈게 orgItem은 SetParent로 새로운 Slot으로 이동했지만 newItem의 경우
parentAfterDrag의 위치 정보만 넘겨받았습니다.
즉 newItem는 아직 SetParen를 이용한 Slot의 변경 없이 아직 root에 머물고 있습니다.
이렇게 변경된 위치 정보를 실제 옮겨 주는 기능은 OnEndDrag에서 해 주게 됩니다.
그럼 왜 이곳에서 하지 않고 OnEndDrag에서 해주냐 하면 만약 드롭될 곳에 슬롯이 없다면
그럼 OnDrop 이벤트 자체가 일어나지 않게 됩니다.
그땐 OnEndDrag만 실행되고 드래그가 끝나니 이동한 아이템의 위치를 실제 옮겨 주는 곳은 항상 OnEndDrag에서
해 주셔야 합니다.
아이템의 구조와 슬롯에 아이템이 들어왔을 때의 모양입니다.
아이템을 구성하는 컴포넌트들입니다.
마지막으로 아이템의 카운트를 표시할 TextMeshPro를 추가해 주시면 됩니다
위 아이템의 구조를 보시면 됩니다.
현재 구조와 스크립트를 모두 만들었다면 해당 Item을 프리펩으로 만들어 Slot에서 삭제하시면 됩니다.
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class InventoryItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
[Header("Inventory Item Image")]
[SerializeField] private Image image;
[Header("Item Count Text")]
[SerializeField] private TextMeshProUGUI countText;
[HideInInspector] public Item item;
[HideInInspector] public int count;
[HideInInspector] public Transform parentAfterDrag;
/// <summary>
/// 아이템 초기화
/// </summary>
/// <param name="newItem">Item Data</param>
public void InitialiseItem(Item newItem, int count = 1)
{
item = newItem;
image.sprite = newItem.itemImage;
this.count = count;
RefreshCount();
}
/// <summary>
/// 아이템의 Count를 입력한다.
/// </summary>
public void RefreshCount()
{
countText.text = $"{count}";
}
/// <summary>
/// 아이템 버튼 기능
/// </summary>
public void SlotButton()
{
//
}
/// <summary>
/// 처음 Drag가 시작 될때
/// </summary>
public void OnBeginDrag(PointerEventData eventData)
{
image.raycastTarget = false;
countText.enabled = false;
parentAfterDrag = transform.parent;
transform.SetParent(transform.root);
transform.localScale = new Vector3(1.2f, 1.2f, 1.2f);
}
/// <summary>
/// Drag 중일때
/// </summary>
public void OnDrag(PointerEventData eventData)
{
transform.position = eventData.position;
}
/// <summary>
/// Drag의 마지막 처리
/// </summary>
public void OnEndDrag(PointerEventData eventData)
{
image.raycastTarget = true;
transform.SetParent(parentAfterDrag);
transform.localScale = new Vector3(1, 1, 1);
countText.enabled = true;
}
}
추가되는 인테페이스가 몇 개 있습니다.
각각의 기능은 각 메서드 위에 설명이 첨부되어 있으니 참고해 주세요
아직 나오지 않았지만 Inventory Manager에서 아이템이 생성될 때 해당 아이템의 정보를 넘겨받을 때 사용됩니다.
아이템의 수량을 표시해 줍니다.
SlotButton()의 기능은 다음에 구현하도록 하겠습니다.
처음 아이템을 잡고 드래그를 시작할 때 실행되는 이벤트입니다.
image.raycastTarget = false 이벤트 시작과 함께 아이템 이미지의 raycast를 비활성 시켜줘야 다른 슬롯으로
아이템이 이동해 해당 슬롯에서 드롭 이벤트가 발생할 때 영향을 받지 않게 됩니다.
다시 말해 이걸 true인 상태로 두면 이동은 되지만 드롭이 불가능해진다는 말입니다.
countText.enabled =false 이동 중엔 count를 숨겨 둡니다.
parentAfterDrag = transfotm.parent 즉 현재 아이템이 위치한 부모 즉 Slot의 위치 정보를 저장해 둡니다.
위 Drop에서도 설명했지만 Slot이 아닌 위치에 놓이거나 아이템이 있는 Slot에 놓일 때 현 위치 복귀 및 다른 아이템과
위치 교환을 위해 저장해 두는 것입니다.
SetParent(transform.root) 아이템이 움직이기 시작하면 아이템을 최상단 위치로 옮겨 이동시킵니다.
마지막으로 localScale 부분은 아이템이 이동 중에 조금 더 크게 표시해 줍니다.
이 이벤트는 아이템이 움직이고 있을 때 발생하는 이벤트입니다. 즉 Drag의 이동 위치를 아이템 위치로 변환시켜 줍니다.
마지막으로 Drag가 끝나면 실행 되게 됩니다.
역시 위에서 설명했지만 만약 Drop 이벤트가 있다면 Drop의 기능을 먼저 실행 후 마지막으로 EndDrag가 실행됩니다.
Drag가 Slot이 아닌 곳에서 끝났다면 처음 저장해 두었던 시작위치로 다시 아이템을 옮겨 주며
OnDrop 기능을 만났다면 그곳에서 변경된 위치로 아이템을 옮겨 줍니다.
나머지 코드는 아이템의 크기를 원래대로 돌려주며 카운트 텍스트도 다시 활성화시켜 줍니다.
1부는 여기서 마무리하겠습니다.
2부에서는 아이템모델과 아이템을 생성 후 위치를 변경해 보는 내용으로 진행됩니다.
'Unity' 카테고리의 다른 글
유니티 (Unity) - 실전 인벤토리 제작 (3부) (0) | 2025.07.25 |
---|---|
유니티 (Unity) - 실전 인벤토리 제작 (2편) (0) | 2025.07.24 |
유니티 C# - Interface 게임에 적용해 보기 (10) | 2024.07.09 |
유니티 (Unity) - 처음 만들어 보는 인벤토리 이해하기 (Inventory) (30) | 2024.07.09 |
유니티 c# - 델리게이트(Delegate) Action 사용해 보기 (0) | 2024.07.09 |