Unity Engine/Unity UI

[유니티] UI 자동화 #2: Get

Muru 2023. 11. 30. 13:18

 

 

지난번에 바인딩을 하였다. 이제는 바인딩 한 값을 가져와보도록 하려고 한다.

또, UI에 GameObject를 불러오는 법과, Button에서 전부 컨트롤할수 없으므로 스크립트를 나눠 상속 받게 할 것이다.

 


public class UI_Button : MonoBehaviour
{
    Dictionary<Type, UnityEngine.Object[]> _objects = new Dictionary<Type, UnityEngine.Object[]>
    
    private void Start()
    {
        Bind<Button>(typeof(Buttons));
        Bind<Text>(typeof(Texts));
    }

    private void Bind<T>(Type type) wherer T : UnityEngine.Object
    {
    	string[] names = Enum.GetNames(type)	//enum string 변환
        UnityEngine.Object[] objects = new UnityEngine.Object[names.Length];
        _objects.Add(typeof(T), objects);
        
        for (int i = 0; i < name.Length; i++)
        {
            objects[i] = Util.FindChild<T>(gameObject, names[i], true);
        }
    }
}


============================================
이제 바인딩을 했으므로 가져와보자(Get)
private T Get<T>(int index) where T : UnityEngine.Object
{
	UnityEngine.Object[] objects = null;
	if(_objects.TryGetValue(typeof(T), out objects) == false)
    	return null;
    
    return objects[index] as T;
}

===========
Dictionary의 TryGetValue를 이용해 키값을 추출한다.
꺼내는데 성공했다면 object[index]번호를 추출후 T값으로 캐스팅한다.

이후 되는지 확인하기위해

private void Start()
{
        Bind<Button>(typeof(Buttons));
        Bind<Text>(typeof(Texts));

        Get<Text>((int)Texts.ScoreText).text = "Bind TEST";
}

라고 적어보자.

텍스트가 바뀌었다.


이번엔 enum값으로 GameObject를 추가하려고한다. 기존 enum값 아래에 추가를 하고, 바인딩을 해보자.

//...
enum GameObjects
{
    TestObject
}

    private void Start()
    {
        //...
        Bind<GameObject>(typeof(GameObjects));
}

	//...
	for (int i = 0; i < name.Length; i++)
    	objects[i].Utill.FindChild<T>(gameObject, names[i], true)
}

오류가발생한다. 바인딩을해도 컴포넌트에는 GameObject라는것이 없기 때문.

Util에서 GameObject를 받을수있는 FindChild를 생성한다.
그리고 기존 코드에 if문을 추가해서 게임오브젝트인지, T타입인지 체크해서 찾아준다.

for (int i = 0; i < names.Length; i++)
{
	if (typeof(T) == typeof(GameObject))
    	objects[i] = Util.FindChild(gameObject, names[i], true);
    else
    	objects[i] = Util.FindChild<T>(gameObject, names[i], true);
        
    //안전하게 찾았는지 확인
    if (objects[i] == null)
    	Debug.Log($"바인딩 실패: {names[i]}");
}
이제 게임오브젝트와 T타입 모두 찾을수있게되었다.

마지막으로 수정할부분은 Get으로 가져오는 부분이다. 앞으로 Text, Button, Image 등
사용할 일이 많을 것이니 미리 Get버전을 생성해두자.

자주사용하는 애들을 위해 Get을 만들어주고 기존 코드인 
Get<Text>((int)Texts.ScoreText).text = "Bind TEST"; 를
GetText((int)Texts.ScoreText).text = "Bind TEST";로 바꾼다.

이제 UI_Base.cs를 생성해서 상속시켜주면 완료.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UI_Base : MonoBehaviour
{
    protected Dictionary<Type, UnityEngine.Object[]> _objects = new Dictionary<Type, UnityEngine.Object[]>();

    protected void Bind<T>(Type type) where T : UnityEngine.Object
    {
        string[] names = Enum.GetNames(type);   //enum string 변환

        UnityEngine.Object[] objects = new UnityEngine.Object[names.Length];
        _objects.Add(typeof(T), objects); //변환한 string Dictionary에 전달

        //for문으로 순회해서 찾는다: 이름으로
        for (int i = 0; i < names.Length; i++)
        {
            if (typeof(T) == typeof(GameObject))
                objects[i] = Util.FindChild(gameObject, names[i], true);
            else
                objects[i] = Util.FindChild<T>(gameObject, names[i], true);

            if (objects[i] == null)
            {
                Debug.Log($"바인딩 실패: {names[i]}");
            }
        }
    }

    protected T Get<T>(int idx) where T : UnityEngine.Object
    {
        UnityEngine.Object[] objects = null;
        if (_objects.TryGetValue(typeof(T), out objects) == false)
        {
            return null;
        }

        return objects[idx] as T;
    }

    protected Text GetText(int idx) { return Get<Text>(idx); }
    protected Button GetButton(int idx) { return Get<Button>(idx); }
    protected Image GetImage(int idx) { return Get<Image>(idx); }
}
using UnityEngine;
using UnityEngine.UI;

enum Buttons
{
    PointButton
}

enum Texts
{
    PointText,
    ScoreText
}

enum GameObjects
{
    TestObject
}

public class UI_Button : UI_Base
{
    private void Start()
    {
        Bind<Button>(typeof(Buttons));
        Bind<Text>(typeof(Texts));
        Bind<GameObject>(typeof(GameObjects));

        GetText((int)Texts.ScoreText).text = "Bind TEST";
    }

    int _score = 0;

    public void OnButtonClicked()
    {
        _score++;
    }
}

 

이제 바인딩이 완전 끝났으므로, 이벤트를 연동해보도록 하자.