[Unity3D] 인벤토리 [Part 3] - Item Drag & Swap

※ 주의 

이 글은 아마추어가 개인적으로 생각하여 작성하는 것으로, 이곳에 나오는 내용을 맹신하지 않는것을 당부드립니다.



Menu

1. 인벤토리 껍데기 만들기.

- 인벤토리의 Pivot 설정.

- 슬롯의 Pivot 설정.

- 슬롯 사이즈 설정.

- 슬롯 간 거리 설정.

- 슬롯의 가로, 세로 개수 설정.

- 인벤토리의 가로 사이즈, 세로 사이즈 설정.

- 슬롯 생성 및 부모설정.

- 모든 슬롯을 관리해줄 리스트를 생성.


2. 아이템 획득 시 검사조건 만들기 및 슬롯 기능 만들기.

- 아이템을 먹었을 때, 인벤토리 내의 슬롯을 모두 검사한다.

  *검사조건 : -> 슬롯 내에 같은 아이템이 존재하는지?

-> 슬롯내에 같은 아이템이 존재할 경우 겹칠수 있는지?

-> 슬롯내에 같은 아이템이 존재하지만, 겹칠수 없는경우 빈 슬롯이 존재 하는지?

- 슬롯을 스택으로 만들어 아이템 관리하기

  ->아이템이 슬롯에 들어갔을때 이미지 변경.  

  ->아이템을 겹칠경우 텍스트 갱신.

  ->아이템을 사용할 경우 텍스트 갱신.

  ->아이템을 모두 사용했을 때 이미지 변경.


3. 아이템 만들기 및 획득

 - 아이템 타입 설정.

 - 아이템의 이미지 설정.

 - 아이템 겹칠수 있는 최대치 설정.

 - 아이템과의 충돌로 아이템 획득하기.


4. 인벤토리내에 아이템 드래그 앤 드랍으로 아이템 옮기기 및 자리 바꾸기.

 - 처음 마우스 버튼을 누를 때

 - 누르고 이동할 때

 - 드래그가 끝났을 때

 - 누른 버튼을 땠을 때

의 4가지 상태로 나눠 드래그 앤 드랍 구현.


5. XML문서를 이용한 인벤토리 아이템 저장.

- Save

- Load




미리보기





4. 인벤토리내에 아이템 드래그 앤 드랍으로 아이템 옮기기 및 자리 바꾸기.




- 빈 이미지를 만든다.

이 이미지는 슬롯에 있는 아이템을 눌렀을 때 그 아이템의 이미지를 빈 이미지에 가져와 띄워주는 역할을 하는 이미지이다.


빈 이미지를 위와같이 Canvas의 자식으로 하나 만든다.

그리고, 태그를 하나 추가할 건데, 이 태그는 스크립트로 이 이미지를 가져오기 위함니다.

태그의 이름은 DragImg이다.


1
2
3
4
5
6
public Transform Img;   // 비어있는 이미지.
 
void Start()
{
    Img = GameObject.FindGameObjectWithTag("DragImg").transform;
}
cs


다음은 슬롯에 4가지 이벤트를 추가 해보자.

Event Trigger를 추가하면 된다.




드래그 앤 드롭은 4가지 형태로 볼 수 있다.

- 처음 눌렀을 때, (Pointer Down - Down)

- 누르고 드래그 할 때, (Drag - Drag)

- 드래그를 끝냈을 때, (End Drag - DragEnd)

- 마우스 버튼을 땠을 때. (Pointer Up - Up)


1). 처음 눌렀을 때.

 - 슬롯에 아이템이 존재하지 않는다면 함수를 종료한다.

 - 누른 버튼이 마우스 오른쪽 버튼이면 아이템을 사용한다.

 - 빈 이미지 객체를 활성화 시킨다.

 - 빈 이미지의 사이즈를 슬롯의 사이즈와 똑같이 변경한다.

=> 해상도가 달라졌을 때 슬롯의 크기가 바뀌므로 빈 객채의 이미지도 유동적으로 달라져야 한다.

 - 빈 이미지의 sprite를 슬롯이 가지고 있는 아이템 이미지로 변경한다.

 - 빈 이미지 객체의 위치를 마우스의 위치로 가져온다.

 - 슬롯의 이미지를 없애준다.

 - 슬롯의 텍스트 숫자를 없애준다.


2). 누르고 드래그 할 때.

 - 슬롯에 아이템이 존재하지 않으면 함수를 종료한다.

 - 빈 이미지의 위치를 마우스의 위치로 가져온다.


3). 드래그가 끝났을 때.

 - 슬롯에 아이템이 존재하지 않으면 함수를 종료한다.

 - 싱글톤을 이용해 인벤토리 내에 있는 Swap함수를 호출. 인자로 자신의 슬롯 스크립트와 빈 이미지의 현재 위치를 보낸다.


4). 마우스 버튼을 땠을 때.

 - 슬롯에 아이템이 존재하지 않으면 함수를 종료한다.

 - 빈 이미지 객체를 비활성화 시킨다.

 - 현재 슬롯의 정보를 업데이트 시킨다.


 마우스를 땠을 때 이벤트는 필요 없을것 같지만 필요하다.

빈 이미지 객체의 비활성화 및 슬롯의 이미지 업데이트에 필요하다.

빈 이미지 객체의 비활성화의 경우 드래그가 끝났을 때 수행해도 되지만,

아이템을 눌렀을 때 마우스를 움직이지 않으면 DragEnd함수는 호출되지 않는다.

그렇기 때문에 빈 이미지 객체의 활성화 조정을 이곳에서 할 필요가 있으며,

마찬가지로 없애주었던 이미지의 복구 또한 이곳에서 해 주어야 한다.



'ItemDrag' Script


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class ItemDrag : MonoBehaviour {
 
    public Transform Img;   // 빈 이미지 객체.
 
    private Image EmptyImg; // 빈 이미지.
    private Slot slot;      // 현재 슬롯에 스크립트
 
    void Start()
    {
        // 현재 슬롯의 스크립트를 가져온다.
        slot = GetComponent<Slot>();
        // 빈 이미지 객체를 태그를 이용하여 가져온다.
        Img = GameObject.FindGameObjectWithTag("DragImg").transform;
        // 빈 이미지 객체가 가진 Image컴포넌트를 가져온다.
        EmptyImg = Img.GetComponent<Image>();
    }
 
    public void Down()
    {
        // 슬롯에 아이템이 없으면 함수종료.
        if (!slot.isSlots())
            return;
 
        // 아이템 사용시.
        if (Input.GetMouseButtonDown(1))
        {
            slot.ItemUse();
            return;
        }
 
        // 빈 이미지 객체를 활성화 시킨다.
        Img.gameObject.SetActive(true);
 
        // 빈 이미지의 사이즈를 변경한다.(해상도가 바뀔경우를 대비.)
        float Size = slot.transform.GetComponent<RectTransform>().sizeDelta.x;
        EmptyImg.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, Size);
        EmptyImg.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, Size);
 
        // 빈 이미지의 스프라이트를 슬롯의 스프라이트로 변경한다.
        EmptyImg.sprite = slot.ItemReturn().DefaultImg;
        // 빈 이미지의 위치를 마우스위로 가져온다.
        Img.transform.position = Input.mousePosition;
        // 슬롯의 아이템 이미지를 없애준다.
        slot.UpdateInfo(true, slot.DefaultImg);
        // 슬롯의 텍스트 숫자를 없애준다.
        slot.text.text = "";
    }
 
    public void Drag()
    {
        // isImg플래그가 false이면 슬롯에 아이템이 존재하지 않는 것이므로 함수 종료.
        if (!slot.isSlots())
            return;
 
        Img.transform.position = Input.mousePosition;
    }
 
    public void DragEnd()
    {
        // isImg플래그가 false이면 슬롯에 아이템이 존재하지 않는 것이므로 함수 종료.
        if (!slot.isSlots())
            return;
 
        // 싱글톤을 이용해서 인벤토리의 스왑함수를 호출(현재 슬롯, 빈 이미지의 현재 위치.)
        ObjManager.Call().IV.Swap(slot, Img.transform.position);
        //slot = null;
    }
 
    public void Up()
    {
        // isImg플래그가 false이면 슬롯에 아이템이 존재하지 않는 것이므로 함수 종료.
        if (!slot.isSlots())
            return;
 
        // 빈 이미지 객체 비활성화.
        Img.gameObject.SetActive(false);
        // 슬롯의 아이템 이미지를 복구 시킨다.
        slot.UpdateInfo(true, slot.slot.Peek().DefaultImg);
    }
}
cs


드래그가 끝나는 함수, 그러니까 DragEnd함수의

Swap()함수를 살펴보도록 하자.


접근 방법은 싱글톤을 이용해서 Inventory스크립트에 접근해서 Swap함수를 호출한다.

이 함수의 인자는 2개를 받고 있는데, 현재 내가 누른 슬롯의 Slot 스크립트와 빈 이미지 객체의 위치이다.


'Inventory' 스크립트의 추가된 함수들을 살펴보자.



이곳 에서는 3가지 함수가 추가되었다.

public Slot NearDisSlot(Vector3 Pos)       // 빈 이미지와 가까운 슬롯을 찾아 반환해주는 함수.

public void Swap(Slot slot, Vector3 Pos)   // 슬롯 끼리의 내용물을 전체적으로 교환 해주는 함수. 

void Swap(Slot xFirst, Slot oSecond)        // Swap함수를 보조 해주는 함수. (두 개의 슬롯의 내용물을 교환한다.) 



이번엔 UpdateInfo() 함수를 살펴보자.

이 함수는 슬롯에 추가된 함수로 아이템 존재유무와 이미지 업데이트의 역할을 맡고 있다.

Slot 스크립트에 아래의 함수를 추가해 주면 된다.


1
2
3
4
5
6
7
8
9
10
11
// 슬롯에 대한 각종 정보 업데이트.
public void UpdateInfo(bool isSlot, Sprite sprite)
{
    this.isSlot = isSlot;
    transform.GetChild(0).GetComponent<Image>().sprite = sprite;
 
    if (slot.Count > 1)
        text.text = slot.Count.ToString();
    else
        text.text = "";
}
cs


또한 이러한 함수가 생겼으므로 Slot 스크립트의 AddItem() 함수에 대해서도

아래와 같이 고칠수 있게 된다.


1
2
3
4
5
6
public void AddItem(Item item)
{
    // 스택에 아이템 추가.
    slot.Push(item);
    UpdateInfo(true, item.DefaultImg);
}
cs