TIL

2024 12 11 TIL

noc777 2024. 12. 11. 21:47

Resource Manager 는 내부 데이터(프리팹,스프라이트 등) 를 관리하는 역할

Data Manager는 외부 데이터(Json,Csv 등) 관리하는 역할

UIManager 는 UI를 리소스에서 불러오고 관리하는 역할

 

매니저를 만들고 관리하는 역할이 어떤 느낌인지 조금은 알것같다.

프로젝트 시작 초기에 이걸 잡아놓았다면 지금 고생하진 않았을텐데

뭔가 물어보고 싶은 것은 많지만 개념정립이 안된 느낌이라

일단 자료를 찾아보면서 연구해보는 수 밖에 없는 것 같다.

그래도 부족한 부분은 특강 녹화본을 보면서 계속 만들어보고 있다.

 

 

public class UIManager : MonoSingleton<UIManager>
{
    //현재 해상도//
    private float ScreenSizeX = 1920; 
    private float ScreenSizeY = 1080;

    private Dictionary<string,UIPopup> UIPopupPool = new Dictionary<string,UIPopup>();
    private Dictionary<string,UIScene> UIScenePool = new Dictionary<string,UIScene>();

    public T CreateUI<T>() where T : UIBase //UI의 생성 메서드
    {
        string uiName = typeof(T).ToString();

        if(typeof(UIPopup).IsAssignableFrom(typeof(T)))
        {
            //팝업 타입의 UI일 경우
            UIPopup ui = ClassifyUI<UIPopup>(uiName,UIPopupPool);
            return ui as T;
        }
        else if(typeof(UIScene).IsAssignableFrom(typeof(T)))
        {
            //고정 타입의 UI일 경우
            UIScene ui = ClassifyUI<UIScene>(uiName,UIScenePool);
            return ui as T;
        }

        Debug.Log("어느 타입의 UI에도 속하지 않음");
        return null;
    }

    private T ClassifyUI<T>(string uiName,Dictionary<string,T> pool) where T : UIBase
    {
        if (pool.ContainsKey(uiName))
        {
            //중복된 키가 있는 것을 생성하려한다면 이미 있는 것을 꺼내서 반환
            T obj = pool[uiName];
            return obj;  
        }
        //키가 없을 경우 새로 리소스를 로드해 생성
        T uiResource = ResourceManager.Instance.LoadResource<T>(FirstType.Prefab, SecondType.UI, uiName);

        Canvas parentCanvas = SetNewCanvas(uiName); 
        T ui = Instantiate(uiResource, parentCanvas.transform); 
        ui.canvas = parentCanvas; 
        ui.name = ui.name.Replace("(Clone)", ""); 
        pool.Add(uiName, ui);

        return ui;
    }

    private Canvas SetNewCanvas(string uiName) //UI캔버스 설정 메서드
    {
        GameObject canvasObject = new GameObject(uiName + "Canvas");

        var canvas = canvasObject.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;

        var canvasScaler = canvasObject.AddComponent<CanvasScaler>();
        canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        canvasScaler.referenceResolution = new Vector2(ScreenSizeX, ScreenSizeY);

        canvasObject.AddComponent<GraphicRaycaster>();

        return canvas;
    }

    public void ShowPopup<T>() where T : UIPopup
    {
        string uiName = typeof(T).ToString();
        UIPopupPool[uiName].Show();
    }

    public void HidePopup<T>() where T : UIPopup
    {
        string uiName = typeof(T).ToString();
        UIPopupPool[uiName].Hide();
    }

    public void ShowAllPopup()
    {
        if(UIPopupPool.Count == 0)
        {
            Debug.Log("No Popup in Dict");
            return;
        }
        //딕셔너리 안에 있는 모든 팝업 UI를 켜줌
        foreach(KeyValuePair<string,UIPopup> popupPool in UIPopupPool)
        {
            popupPool.Value.Show();
        }
    }

    public void HideAllPopup()
    {
        if (UIPopupPool.Count == 0)
        {
            Debug.Log("No Popup in Dict");
            return;
        }
        //딕셔너리 안에 있는 모든 팝업 UI를 꺼줌
        foreach (KeyValuePair<string, UIPopup> popupPool in UIPopupPool)
        {
            popupPool.Value.Hide();
        }
    }
}

 

UI 분류는 (부모)UIBase ,   (자식) UIPopup,UIScene 으로 나누어서 구분하였다.

UIPopup은 인벤토리 창,설정 창 처럼 조작을 통해 On/Off 할 수 있는 UI이고

UIScene은 정신력 게이지, 배터리 잔량 처럼 화면상에 유지되는 UI를 범주로 잡았다.

 

만일 외부 데이터를 받아와서 UI에 반영할 일이 있다면 수정을 거치겠지만

현재는 리소스 로드로만 UI를 불러오고 있다.

 

이후 추가할 것은 UIScene 분류의 UI가 비디오 연출 시에 화면 밖으로 잠깐 나갈 수 있도록 기능을 만들고

Dotween으로 테스트를 해볼 예정이다.

 

그리고 DataManager 의 사례를 찾아보면서 프로젝트에 어떻게 적용시켜야할 지 생각을 해봐야할 것 같다.

이후 전임자가 맡았던 인벤토리를 수정하고 한사이클을 만드는 데 집중해보고 싶다.

 

제네릭을 통해 한번에 묶고 거기서 타입을 분류하는 과정에서

해당 클래스가 부모클래스를 상속받고 있는지 여부를 판별하는 조건을 만들 때

IsAssignableFrom 이라는 키워드를 사용하였다.

역할 자체는 is 키워드(키워드)와 같다. 

//T 가  UIPopup에서 파생되었는지
typeof(UIPopup).IsAssignableFrom(typeof(T))

그리고 (T)로 형변환이 안되는 경우 as 키워드를 통해 형변환을 하였는데 

as 키워드를 사용하지 않으면 (T)(Object) 와 같은 형변환이 이루어져야 한다고 한다. 

 

다만 as 는 조건에 성립하지 않으면 null을 반환한다고 하니 해당 예외처리는 꼭 필요해보인다.

 

Is 키워드 :

객체가 특정 타입으로 변환가능한지 검사하는 키워드

true 와 false 로 결과를 반환하여 if문에 쓰기 좋다.

실제로 변환하지는 않는다.

 

As 키워드 :

객체를 특정 타입으로 변환시키는 키워드

변환이 가능하면 해당 타입으로 변환시켜 반환하고 불가능하면 null을 반환한다.

따라서 사용할 땐 null을 반환할 경우를 고려해야한다.

 

자주 썻던 키워드가 아니라 헷갈려서 따로 적어둠

'TIL' 카테고리의 다른 글

2024 12 13 TIL  (0) 2024.12.13
2024 12 12 TIL  (1) 2024.12.12
2024 12 10 TIL  (0) 2024.12.10
2024 12 09 TIL  (0) 2024.12.09
2024 12 06 TIL  (0) 2024.12.06