[Unity] Enum에 컴포넌트 맵핑하기

dd_ddong·2022년 5월 29일
0

Unity

목록 보기
5/9

UI 이벤트 발생시

UI에서 버튼이벤트를 추가하기 위해서 유니티툴에서 CallBack으로 호출할 메소드만 지정해주면 된다. 위의 경우 UI오브젝트에 있는 UI_ButtonScript에 있는 OnButtonClicked메소드를 지정했다.

이를 위해 UI_ButtonScript에서는 SerializeField나 public 필드로 Button 클릭시 변화를 줄 컴포넌트를 지정해줘야 한다.


하지만 UI에서 관리해야할 버튼이 많아지고 이벤트 발생시 영향을 줄 컴포넌트들이 증가한다면 이 방법은 오류가 발생하기 쉬워진다.

UI 자동화

UI에 있는 컴포넌트들을 UI Script안에서 접근가능하게 맵핑해놓는다면 SerializeField나 public 필드로 하나하나 지정할 필요가 없어진다.


지금 UI 안에 있는 구성요소들을 스크립트에서 enum 형식을 이용해 맵핑할 형식을 만들어준다.

public class UI_Button : MonoBehavior
{
	enum Buttons
    {
    	PonintButton
    }
    enum Texts
    {
    	PointText,
        ScoreText
    }
    //Button Event에서 사용한 Callback 함수
    public void OnButtonClicked()
    {
        Debug.Log("ButtonClicked");

        _score++;
        _text.text = $"score : {_score}";
    }
}

Text 컴포넌트는 Texts enum형식에 묶고 각각의 Text에 대응되는 Enum 요소를 만들어준다.
이 때 이름을 일치하게 만들어줘야 헷갈리지 않고 이름비교를 통해 맵핑시켜줄수 있다.

이제 실제 맵핑을 실행하는 Bind 메소드와 맵핑한 컴포넌트를 가져오는 Get 메소드를 만들어보자.

public class UI_Button : MonoBehavior
{
	//컴포넌트의 참조를 담고있는 dictionary
	Dictionary<Type, UnityEngine.Object[]> _objects = new Dictionary<Type, UnityEngine.Object[]>();
    
	void Bind<T>(Type type) where T : UnityEngine.Object
    {
    	//Enum  요소들을 string 배열에 할당
    	string[] names = Enum.GetNames(type);
        //Enum 요소 갯수와 같은 크기의 배열생성
        UnityEngine.Object[] objects = new UnityEngine.Object[names.Length];
        //Dictionary에 추가
        _objects.Add(typeof(T), objects);
        
        for(int i = 0; i<names.Length; i++)
        {
        	//name이 일치하는 Component를 찾아 할당해준다
        	objects[i] = FindChild(gameObject, names[i], true);
        }
   }
   T Find<T>(GameObject go, string name = null, bool recursive = false) where T : UnityEngine.Object
   {
   		if(go == null)
        	return null;
        //자식들만 탐색
        if(recursive == false)
        {
        	for(int i=0; i<go.transform.childCount; i++)
            {
            	//i 번째 자식할당
            	Transform transform = go.transform.GetChild(i);
                // 이름이 없다면 같은 컴포넌트이니까 통과 이름이 있을때는 같아야지 통과
                if(string.IsNullOrEmpty(name) || transform.name == name)
                {
                	T component = transform.GetComponent<T>();
                    if(component != null)
                    	return component;
                }
            }
            //자식의 자식까지 탐색
        else
        {
        	//T형식의 모든 자식들을 탐색
        	foreach(T component in go.GetComponentsInChildren<T>())
            {
            	if(string.IsNullOrEmpty(name) || transform.name == name)
                	return component;
            }
        }
        
        return null;
    }

                	
   
}

get

    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;

    }

활용

public class UI_Button : MonoBehavior
{
	void Start
    {
    	Bind<Text>(typeof(Texts));
        
        Get<Text>((int)Text.ScoreText).text = "Bind Test";
    }
}

0개의 댓글