먼저 BaseUI를 만들어준다(모든 UI가 상속)
public abstract class BaseUI : MonoBehaviour
{
//파괴될 시 UI매니저의 딕셔너리에서 자기 자신을 제거.(비활성화됬음을 알림)
protected virtual void OnDestroy()
{
UIManager.Instance.RemoveUIInList(GetType().Name);
}
}
그리고 팝업용으로 표시되는 PopupUI를 만든다.
public abstract class PopupUI : BaseUI
{
}
public class UIManager : Singleton<UIManager>
{
//현재 활성화된 UI를 저장할 리스트.
[Header("No Need to Allocate")]
private Dictionary<string, BaseUI> uiList;
public Canvas mainCanvas;
protected override void Awake()
{
base.Awake();
uiList = new Dictionary<string, BaseUI>();
GameObject obj = GameObject.Find("MainCanvas");
//본인의 경우 UICamera를 따로 두고 메인 카메라는 UI레이어를 제외하고 렌더링하게함.
//그렇기에 캔버스의 렌더모드가 다르다. 해당 이름에 맞는 오브젝트를 찾고 없으면 생성.
if (obj == null)
{
mainCanvas = Instantiate(ResourceManager.Instance.Load<GameObject>(ResourceType.UI, "MainCanvas").GetComponent<Canvas>());
mainCanvas.renderMode = RenderMode.ScreenSpaceCamera;
mainCanvas.worldCamera = GameManager.Instance.uiCam;
mainCanvas.planeDistance = 900f;
}
else
{
mainCanvas = obj.GetComponent<Canvas>();
mainCanvas.worldCamera = GameManager.Instance.uiCam;
}
}
//해당 오브젝트를 보여주고 리턴. 또한 활성화 딕셔너리에 추가.
public T show<T>() where T : BaseUI
{
string key = typeof(T).Name;
var uiPrefab = ResourceManager.Instance.Load<T>(ResourceType.UI, typeof(T).Name);
var uiInstance = Instantiate(uiPrefab, mainCanvas.transform);
uiList[key] = uiInstance;
return uiInstance;
}
//활성화된 UI 중 타입에 맞는 UI를 반환.
public T Get<T>() where T: BaseUI
{
string key = typeof(T).Name;
if (uiList.TryGetValue(key,out BaseUI ui))
{
return ui as T;
}
Debug.LogWarning($"UI Not Found: {key}");
return null;
}
}
이런 식으로 스크립트를 구성하면 리소스매니저에서 UI를 가져오는데.
프리팹 이름과 스크립트의 이름을 통일시켜야한다.
예시)

참고로 프리팹화는

이런 상태에서 진행해야한다. 안 그러면 메인 캔버스를 자식으로 만들 때 오류남.
그리고 스크립트의
mainCanvas.worldCamera = GameManager.Instance.uiCam;
uiCam은 보시다시피 다른 매니저에서 관리중.