'참된코딩'에 해당되는 글 1건

  1. 2017.04.23 [Unity3D] 인벤토리 [Part 4] - Save 3

[Unity3D] 인벤토리 [Part 4] - Save

※ 주의 

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



Menu

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

- 인벤토리의 Pivot 설정.

- 슬롯의 Pivot 설정.

- 슬롯 사이즈 설정.

- 슬롯 간 거리 설정.

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

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

- 슬롯 생성 및 부모설정.

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


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

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

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

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

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

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

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

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

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

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


3. 아이템 만들기 및 획득

 - 아이템 타입 설정.

 - 아이템의 이미지 설정.

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

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


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

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

 - 누르고 이동할 때

 - 드래그가 끝났을 때

 - 누른 버튼을 땠을 때

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


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

- Save

- Load


미리보기





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


인벤토리에 들어있는 아이템의 정보를 XML문서에 Save하여,

게임 시작 시 XML문서를 토대로 정보를 Load하려고 한다.


시작하기 전에 Save및 Load의 호출를 어디에서 할 것인가 부터 살펴보자.


Save는 인벤토리 내에 아이템에 대한 정보변환이 일어났을 때 수행해야한다.

그렇다면 정보변환는 언제 일어나는 것일까?


- 아이템을 먹었을 때

- 아이템을 드래그하여 다른 슬롯으로 옮겼을 때.

- 아이템 끼리 Swap했을 때.

이 모든 변화가 일어났을 때 Save는 호출되어야 한다.

우리가 만든 함수 중 위의 변화가 일어났을 때

어김없이 호출되는 함수가 하나 있다.


'Slot' 스크립트에 존재하는 UpdateInfo() 함수이다.

이 함수는 위의 모든 상황에서 호출되는 함수다.


1
2
3
4
5
6
7
8
9
10
11
12
13
// 슬롯에 대한 각종 정보 업데이트.
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 = "";
 
    ItemIO.SaveDate();
}
cs


※ 이렇게 맨 밑에다 Save를 호출하면 된다.


그렇다면 Load는 언제 호출되어야 할까?

인벤토리가 만들어지기 전에 Load가 호출되면 안된다.


인벤토리가 생성되고.

슬롯이 생성되고(Inventory 스크립트의 Awake()함수의 호출).

슬롯객체에 붙어있는 Slot 스크립트의 Start()가 호출이 끝난 뒤.

Load가 호출되어야 한다.



Save함수를 호출할 때 아이템에대한 정보가 XML문서로 만들어지게 된다.

이 스크립트를 이해하기 위해서는 우리는 XML문서가 어떻게 구성되어 있는지 파악할 필요가 있다.


정보가 저장된 XML문서의 구성은 이렇다.


1
2
3
4
5
6
7
8
9
10
11
<ItemDB>
  <Item SlotNumber="1" Name="MP" Count="3" MaxCount="3" />
  <Item SlotNumber="2" Name="MP" Count="3" MaxCount="3" />
  <Item SlotNumber="4" Name="HP" Count="3" MaxCount="3" />
  <Item SlotNumber="5" Name="MP" Count="3" MaxCount="3" />
  <Item SlotNumber="6" Name="MP" Count="3" MaxCount="3" />
  <Item SlotNumber="8" Name="HP" Count="3" MaxCount="3" />
  <Item SlotNumber="9" Name="HP" Count="3" MaxCount="3" />
  <Item SlotNumber="17" Name="HP" Count="1" MaxCount="3" />
  <Item SlotNumber="18" Name="MP" Count="1" MaxCount="3" />
</ItemDB>
cs



<요소> 

<필드이름 정보1 정보2 정보3 정보4.../>

<필드이름 정보1 정보2 정보3 정보4.../>

</요소>


이런식으로 구성이 되어있는데, 이것을 스크립트로 만들어 내보낼 것이다.


XML문서를 만드는 스크립트의 흐름은 이렇다.


1. XML문서를 하나 만든다.

2. 요소를 하나 만든다.

3. 만든 요소를 XML문서에 첨부한다.


여기까지 코드를 짜면 XML문서는


---------------------------------

<요소>


</요소>

---------------------------------

까지 생성이 된다.


4. 필드(요소)를 생성.

5. 필드(요소)의 내용을 셋팅.

6. 첫 번째 요소의 방금만든 필드(요소)를 첨부.


까지 하면 위의 완성된 XML문서가 완성되며,

마지막으로 XML를 정해진 경로로 내보내면 저장은 끝난다.


코드를 한 번 보도록 하자.


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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;
 
// sealed을 사용하여 다른 클래스가 상속되지 못하도록 함.
public sealed class ItemIO
{
    public static void SaveDate()
    {
        // 인벤토리에서 슬롯을 관리해주는 리스트를 받아온다.
        List<GameObject> item = ObjManager.Call().IV.AllSlot;
 
        XmlDocument XmlDoc = new XmlDocument();             // XML문서 생성.
        XmlElement XmlEl = XmlDoc.CreateElement("ItemDB");  // 요소 생성.
        XmlDoc.AppendChild(XmlEl);                          // 요소를 XML문서에 첨부.
 
        // 리스트의 총 크기(슬롯의 개수.)
        int Count = item.Count;
 
        for (int i = 0; i < Count; i++)
        {
            // 슬롯 리스트에서 슬롯을 하나씩 꺼내온다.
            Slot itemInfo = item[i].GetComponent<Slot>();
 
            // 슬롯이 비어있으면 저장할 필요가 없으므로 넘긴다.
            if (!itemInfo.isSlots())
                continue;
 
            // 필드(요소)를 생성.
            XmlElement ElementSetting = XmlDoc.CreateElement("Item");
 
            // 필드(요소)의 내용을 셋팅.
            ElementSetting.SetAttribute("SlotNumber", i.ToString());                    // n번째 슬롯에 아이템.
            ElementSetting.SetAttribute("Name", itemInfo.ItemReturn().Name);            // 아이템의 이름.
            ElementSetting.SetAttribute("Count", itemInfo.slot.Count.ToString());       // 아이템의 개수. (ex: 현 슬롯에 겹쳐진 아이템 10개임.)
            ElementSetting.SetAttribute("MaxCount", itemInfo.ItemReturn().MaxCount.ToString()); // 아이템을 겹칠수 있는 한계.
            XmlEl.AppendChild(ElementSetting);                                          // ItemDB요소에 위의 셋팅한 요소를 문서에 첨부.
        }
 
        // XML문서로 내보낸다. 인자로는 문서를 내보낼 경로.
        XmlDoc.Save(Application.dataPath + "/Save/InventoryData.xml");
    }
}
cs



1
using System.Xml;
cs


필수는 아니지만 각 함수를 사용할 때 System.Xml을 쓰는건 효율이 떨어지므로 using해둡시다.


1
XmlDocument XmlDoc = new XmlDocument();
cs


Document는 문서라는 뜻으로 XML문서를 만듭니다.


1
XmlElement XmlEl = XmlDoc.CreateElement("ItemDB");
cs


Element는 요소,성분이라는 뜻으로 새로운 요소를 인자의 이름으로 만든다.

이 구문에서 XML문서의 <ItemDB> </ItemDB>가 완성된다.


1
XmlDoc.AppendChild(XmlEl);
cs


Append는 첨부라는 뜻으로 요소를 XML문서에 첨부하는데 사용한다.


쭉 보면


1. XML문서를 만들고

2. <ItemDB> </ItemDB>라는 요소를 만들어서

3. XML문서에 첨부.

라는 것이 된다.


그 다음 for문을 돌려 필드를 생성시켜야 하는데, 이것은 무엇에 대한 for문일까?


우리는 인벤토리에 각 슬롯이 가지고있는 아이템에 대한 정보를 저장하는 것이다

만약 슬롯이 30개 존재한다고 하면 for문을 30개 돌아 각 슬롯이 가진 정보를 필드에 옮겨 저장하는 것이다.


슬롯 개수에 대한 정보는 인벤토리 스크립트가 가지고 있으므로 가져와서 

슬롯의 숫자만큼 for문을 돌면 된다.

for문을 돌때 슬롯에 아무것도 존재하지 않는다면 저장할 필요가 없으므로 continue해준다.


여기서 우리가 저장할 내용은 이렇다.


1. 슬롯의 번호

2. 아이템의 이름.

3. 아이템의 개수.

4. 아이템을 겹칠수 있는 한계 개수.


이렇게 4개에 대한 정보를 저장해야 한다.


슬롯의 번호를 저장하는 이유는 

아이템이 2번째 칸에 있고, 게임을 껏다 켰을 때 그 아이템은 여전히 2번째 칸에 존재 해야한다. 

Load할때 슬롯의 번호를 모르고 있다면 몇번째 슬롯에 아이템정보를 가져와야할지 알지 못하기 때문이다.


아무튼

for문을 돌면서

1
XmlElement ElementSetting = XmlDoc.CreateElement("Item");
cs

또 하나의 필드(요소)를 생성한다. 이름은 "Item"이다.

이 필드(요소)에 위의 4가지 정보를 셋팅해준다.


1
2
3
4
  ElementSetting.SetAttribute("SlotNumber", i.ToString());                              // n번째 슬롯에 아이템.
  ElementSetting.SetAttribute("Name", itemInfo.ItemReturn().Name);                      // 아이템의 이름.
  ElementSetting.SetAttribute("Count", itemInfo.slot.Count.ToString());                 // 아이템의 개수. (ex: 현 슬롯에 겹쳐진 아이템 10개임.)
  ElementSetting.SetAttribute("MaxCount", itemInfo.ItemReturn().MaxCount.ToString());  // 아이템을 겹칠수 있는 한계.
cs

※ 모두 문자열로 저장시켜야 한다.


Item이라는 필드에 위의 4가지 정보가 추가되면

이 추가된 정보를 첫 번째 요소인 "ItemDB"에 첨부시켜야 한다.

1
XmlEl.AppendChild(ElementSetting);
cs



이렇게 기본적인 XML문서가 완성된다.

이제 이 XML문서를 내보내면 저장이 되는 것이다.


1
XmlDoc.Save(Application.dataPath + "/Save/InventoryData.xml");
cs


Application.dataPath는 현재 자신의 유니티 프로젝트에 Assets폴더까지의 경로를 반환해준다.

필자같은경우 Assets폴더 안에 Save라는 폴더를 만들었고 그 안에 XML문서가 저장되는데,

문서가 저장될때 이름이 InventoryData.xml이다.



prev 1 next