Programming/Unity

UGUI를 사용한 캐릭터 리스트 UI (소스코드)

사기꾼프로드 2017. 9. 23. 18:26

<캔버스 추가>


우선 UI추가를 위해 캔버스를 추가해줍니다.


<캔버스 인스펙터>


설정 한 캔버스 인스펙터 입니다. UI용 카메라에 찍히도록 설정하기 위해 RenderMode를 Screen Space - Camera로 변경 후


Render Camera에 UI를 찍을 카메라를 넣어줍니다.


저는 UI가 1280 x 720 사이즈로 나오게 하기 위해 Canvas Scaler 에서 저 설정대로 해주었습니다.


UGUI는 캔버스 하나당 메시가 생성되기 때문에 드로우콜을 줄이기 위해 캔버스는 하나로 쓰도록 하고


캔버스 아래에 Panel을 추가해 그 밑에 UI 작업을 한 후 프리팹으로 묶어 사용하도록 하겠습니다.


<스크롤뷰 추가>


리스트를 표기할 스크롤 뷰를 추가해줍니다.


<스크롤뷰 인스펙터>


스크롤바가 필요하다면 Scroll Rect에서 삭제하지 않으시면 되지만 저는 필요가 없음으로 제거해놨습니다.


Scroll Rect 에서 스크롤 될 방향과 민감도나 스크롤뷰 움직임 타입을 변경하실 수 있습니다.


<뷰포트 인스펙터>


뷰포트을 클릭 후 인스펙터를 보시면 Image 파일에 UIMask라는 게 있는데 필요없는 Image라고 해서 지우시면 안됩니다.


지우시게 되면 클립핑이 안되게 되니 주의하세요.


<복사 사용할 오리지날 슬롯>


캐릭터들의 리스트를 만들것이기 때문에 캐릭터 기본적으로 캐릭터 초상화와 슬롯 배경, 슬롯프레임 을 표기할 캐릭터 슬롯


오브젝트를 만들었습니다. 이것을 복사해 사용할 것이기 때문에 _Ori라는 코드를 넣어주었습니다.


<오리지날 슬롯에 Button 컴포넌트 추가>


버튼 컴포넌트를 추가해 OnClick 이벤트에 스크립트를 추가하는 UI_CharList 오브젝트를 당겨 놓고


public으로 설정한 Onclicked 변수를 설정한 후 오리지날 슬롯 오브젝트를 끌어다가 인자로 넣습니다.


이렇게 되면 복사 생성한 슬롯들도 자기자신을 인자로 가지고 이벤트에 전달합니다.


<코드내용>


내용에 주석으로 추가설명을 달아놓았습니다.


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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
 
// 캐릭터 정보 클래스
public class CharInfo
{
    int Lv;
    string CharName;
}
 
public class UI_CharListBox : MonoBehaviour {
 
    // 캐릭터 슬롯 오리지날 오브젝트
    GameObject CharSlotOri = null;
    // 자식오브젝트를 관리하기 위한 딕셔너리
    Dictionary<string, GameObject> MyChildren = new Dictionary<string, GameObject>();
    // 캐릭터 리스트 정보를 가질 클래스 리스트
    List<CharInfo> CharListInfo = new List<CharInfo>();
    // 캐릭터 리스트 오브젝트를 저장할 리스트
    List<GameObject> MyCharList = new List<GameObject>();
    // 캐릭터 리스트 오브젝트 재사용을 위해 저장할 리스트
    List<GameObject> MyCharList_Recycle = new List<GameObject>();
 
    void Awake()
    {
        // 가장 먼저실행되는 Awake에서 자식 오브젝트들을 관리하기 편하게 딕셔너리로 해준다.
        SetChildrenMap(gameObject);
    }
 
    void SetChildrenMap(GameObject TargetObj)
    {
        for (int i = 0; i < TargetObj.transform.childCount; ++i)
        {
            Transform ChildTransform = TargetObj.transform.GetChild(i);
            // 오브젝트 이름을 Key로 하였기 때문에 오브젝트 이름으로 불러와 사용
            MyChildren.Add(ChildTransform.name, ChildTransform.gameObject);
 
            // 자식 오브젝트가 있다면 재쉬호출로 모두 추가해준다.
            if (ChildTransform.transform.childCount > 0)
            {
                SetChildrenMap(ChildTransform.gameObject);
            }
        }
    }
 
    // Use this for initialization
    void Start ()
    {
        // 더미 값 추가
        for (int i = 0; i < 40++i)
        {
            CharInfo info = new CharInfo();
            CharListInfo.Add(info);
        }
 
        // 리스트 생성
        Create_CharList(CharListInfo);
    }
    
    // Update is called once per frame
    void Update ()
    {
    
    }
 
    void Create_CharList(List<CharInfo> _CharListInfo)
    {
        // 다시 불러오는 번거로움이 없게 한번만 설정
        if (CharSlotOri == null)
        {
            CharSlotOri = MyChildren["CharSlot_Ori"];
            CharSlotOri.SetActive(false);
        }
 
        // 재사용 리스트에 현재 리스트를 추가하고 기존 리스트는 비운다
        for ( int i = 0; i < MyCharList.Count; ++i)
        {
            MyCharList[i].SetActive(false);
            MyCharList_Recycle.Add(MyCharList[i]);
        }
        MyCharList.Clear();
 
        for (int i = 0; i < _CharListInfo.Count; ++i)
        {
            GameObject NewChar;
            // 리스트 생성 or 재사용
            if(MyCharList_Recycle.Count > 0)
            {
                NewChar = MyCharList_Recycle[0];
                MyCharList_Recycle.RemoveAt(0);
                // 재사용을 할 경우 추가된 데이터컨테이너는 클리어해준 후 값 다시 추가
                CustomDataConatiner DataContainer = NewChar.GetComponent<CustomDataConatiner>();
                DataContainer.Clear();
                DataContainer.SetValue<bool>(NewChar.name, i % 2 == 0 ? false : true);
            }
            else
            {
                NewChar = Instantiate<GameObject>(CharSlotOri);
 
                // 추가적으로 오브젝트 하나당 데이터관리를 위해 추가해준다.
                CustomDataConatiner DataContainer = NewChar.AddComponent<CustomDataConatiner>();
                DataContainer.SetValue<bool>(NewChar.name, i % 2 == 0 ? false : true);
            }
 
            // 되도록 StringBuilder를 이용해서 스트링을 조합 후 이름 설정
            StringBuilder NameBuilder = new StringBuilder();
            NameBuilder.Append("CharSlot_");
            NameBuilder.Append(i + 1);
            NewChar.name = NameBuilder.ToString();
 
            // 오리지날의 부모와 스케일과 로테이션을 가져와 설정해준다.
            NewChar.transform.SetParent(CharSlotOri.transform.parent);
            NewChar.transform.localScale = CharSlotOri.transform.localScale;
            NewChar.transform.rotation = CharSlotOri.transform.rotation;
 
            // 위치 설정
            // 108는 오브젝트의 크기다 되도록 숫자를 안쓰고 오브젝트의 이미지 사이즈를 가져와 설정하는게 좋다.
            (NewChar.GetComponent<RectTransform>()).localPosition = new Vector3((i % 5* 108-(i / 5* 1080);
 
            // 다 설정된 오브젝트는 활성화 시켜 보여준 후 리스트에 추가해 관리한다.
            NewChar.SetActive(true);
            MyCharList.Add(NewChar);
        }
 
        // 스크롤뷰의 Content는 추가된 구성요소에 따라 크기가 변환되어야 스크롤이 정상적으로 되므로
        // 구성요소의 숫자에 따라 y 크기를 가변해주고 위치를 변경해준다.
        RectTransform CharListContentRect = (MyChildren["Content_CharList"].GetComponent<RectTransform>());
        CharListContentRect.sizeDelta = new Vector2(CharListContentRect.sizeDelta.x, (MyCharList.Count / 5* 108);
        CharListContentRect.transform.localPosition = 
        new Vector3(CharListContentRect.localPosition.x, -(MyCharList.Count / 5* 108, CharListContentRect.localPosition.z);
    }
 
    // 버튼 이벤트에 추가해주기 위해서 public으로 설정
    public void OnClicked(GameObject _ClickedObj)
    {
        // 클릭 되어진 오브젝트의 이름을 로그로 찍어준다.
        StringBuilder builder = new StringBuilder();
        builder.Append("OnClicked : ");
        builder.Append(_ClickedObj.name); 
        print(builder.ToString());
 
        // 커스텀데이터 컨테이너에 추가되었던 값들을 불러와 로그를 찍어준다.
        CustomDataConatiner ClickedData = _ClickedObj.GetComponent<CustomDataConatiner>();
        if (ClickedData != null)
        {
            builder.Remove(0, builder.Length);
            builder.Append(_ClickedObj.name);
            builder.Append(" bool Data : ");
            builder.Append(ClickedData.GetValue<bool>(_ClickedObj.name));
            print(builder.ToString());
        }
 
    }
}
 
cs


스크립트는 UI 프리팹의 최상단인 UI_CahrList 패널에 추가해줍니다.



정상적으로 리스트가 추가되어 스크롤 된다면 완성입니다.