Chapter 7-5. UI : UI Manager (팝업UI들 스택처럼 관리)
카테고리: Unity Lesson 2
태그: Unity Game Engine
인프런에 있는 Rookiss님의 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 7. UI
🚀 UI 자동화를 위한 클래스 구조
- 📜Managers 👉 📜UIManager 를 싱글톤으로 관리
UIManager _ui = new UIManager(); public static UIManager UI { get { return Instance._ui; } }
- 📜PlayerController 👉 📜UIManager의 UI 캔버스 프리팹 생성해주는 ShowPopupUI(팝업 UI 경우) 함수를 호출시켜 UI 띄우기
void Start() { Managers.Input.MouseAction -= OnMouseClicked; Managers.Input.MouseAction += OnMouseClicked; // TEMP Managers.UI.ShowPopupUI<UI_Button>(); }
- 📜UIManager 는 게임 씬 상에서 생길 여러가지 *UI 캔버스 프리팹* 들의 생성과 삭제를 관리하는 스크립트로 사용할 것이다.
- 팝업 UI 캔버스들은 렌더링 순서 또한 관리되어야 한다.
sort order
- 팝업 UI 캔버스들은 렌더링 순서 또한 관리되어야 한다.
캔버스 UI 종류
이 포스트 상에선 두가지로 구분
- 고정UI (씬단위로 항상 화면 고정)
- 대표 조상 📜UI_Scene
- 📜UI_Inven
- 대표 조상 📜UI_Scene
- 팝업UI (사용자가 클릭해야 활성화, 가장 나중에 띄운 팝업부터 비활되도록 Stack 으로 관리할 것)
- 대표 조상 📜UI_PopUp
- 📜UI_Button
- 대표 조상 📜UI_PopUp
📜UI_Base
public abstract void Init();
📜UI_PopUp
public class UI_Popup : UI_Base
{
public override void Init()
{
Managers.UI.SetCanvas(gameObject, true);
}
public virtual void ClosePopupUI() // 팝업이니까 고정 캔버스(Scene)과 다르게 닫는게 필요
{
Managers.UI.ClosePopupUI(this);
}
}
- UI 캔버스 세팅 (오브젝트에 Canvas 컴포넌트 sorting order 세팅) 👉 Init
- 📜UIManager 의 SetCanvas 호출
- 팝업 UI니까 캔버스들을 sorting 해야 하므로
true
전달 (밑에 📜UIManager 참고)
- 팝업 UI니까 캔버스들을 sorting 해야 하므로
- 📜UIManager 의 SetCanvas 호출
- UI 닫기 (캔버스 프리팹 파괴) 👉 ClosePopupUI
- 팝업이니까 고정 캔버스(Scene)과 다르게 닫는게 필요
- 📜UIManager 의 ClosePopupUI 호출
📜UI_Scene
public class UI_Scene : UI_Base
{
public override void Init()
{
Managers.UI.SetCanvas(gameObject, false);
}
}
- UI캔버스 세팅 (오브젝트에 Canvas 컴포넌트 sorting order 세팅) 👉 Init
- 📜UIManager 의 SetCanvas 호출
- 고정 UI니까 sorting 할 필요가 없으므로
false
전달 (밑에 📜UIManager 참고) 고정 UI는 그냥sort order
값이 가장 최소값인 0 으로 고정시킬 것. (가장 먼저 그려져 밑에서 그려지게)
- 고정 UI니까 sorting 할 필요가 없으므로
- 📜UIManager 의 SetCanvas 호출
🚀 UI Manager
- SetCanvas 👉
go
오브젝트의 캔버스 컴포넌트 가져와(GetOrAddComponent를 통해 없다면 붙여서라도 가져옴)sort order
값 세팅 - Show~ 👉 캔버스 UI 프리팹 생성
- Close~ 👉 캔버스 UI 오브젝트 파괴
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager
{
int _order = 10; // 현재까지 최근에 사용한 오더
Stack<UI_Popup> _popupStack = new Stack<UI_Popup>(); // 오브젝트 말고 컴포넌트를 담음. 팝업 캔버스 UI 들을 담는다.
UI_Scene _sceneUI = null; // 현재의 고정 캔버스 UI
public GameObject Root
{
get
{
GameObject root = GameObject.Find("@UI_Root");
if (root == null)
root = new GameObject { name = "@UI_Root" };
return root;
}
}
- 고정 UI
sort order
값이 0 으로 고정. (가장 먼저 그려져 밑에서 그려지게)- 스택으로 관리될 필요 없음. 가장 바탕이 되는 UI이므로 하나만 있으니!
- 팝업 UI
sort order
을 편의상 고정 UI와 겹치지 않도록 10부터 시작하게 할 것이다. 팝업 캔버스 UI들은 10, 11, 12, 13,… 렌더링 순서를 부여받음. 늦게 생성된 것일 수록 늦은 순서! (가장 위에 그려지도록)- 여러개가 생길 수 있으며, 가장 나중에 생성된 팝업부터 먼저 닫혀야 하므로 생성된 팝업 캔버스 UI 오브젝트들을 스택으로 관리할 것.
@UI_Root
라는 이름의 오브젝트를 없다면 만들어서라도 리턴해주는 프로퍼티Root
- 이게 필요한 이유는, Hierarchy 상의 오브젝트들도 마치 폴더 안에 있는것처럼 관련 있는 것들끼리 종류별로 이름을 구분한 빈 오브젝트의 자식으로 넣어 정리할 것이기 때문이다. UI 오브젝트들은 이
@UI_Root
빈 오브젝트 아래에 생성되게 그룹화할 것이라서 필요.
- 이게 필요한 이유는, Hierarchy 상의 오브젝트들도 마치 폴더 안에 있는것처럼 관련 있는 것들끼리 종류별로 이름을 구분한 빈 오브젝트의 자식으로 넣어 정리할 것이기 때문이다. UI 오브젝트들은 이
public void SetCanvas(GameObject go, bool sort = true)
{
Canvas canvas = Util.GetOrAddComponent<Canvas>(go);
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.overrideSorting = true; // 캔버스 안에 캔버스 중첩 경우 (부모 캔버스가 어떤 값을 가지던 나는 내 오더값을 가지려 할때)
if (sort)
{
canvas.sortingOrder = _order;
_order++;
}
else // soring 요청 X 라는 소리는 팝업이 아닌 일반 고정 UI
{
canvas.sortingOrder = 0;
}
}
오브젝트의 캔버스 세팅
canvas
에 Canvas 컴포넌트 가져옴(없으면 붙여서라도)- 캔버스의 RenderMode를 ScreenSpaceOverlay 모드로 세팅
overrideSorting
을 통해 혹시라도 중첩캔버스라 자식 캔버스가 있더라도 부모 캔버스가 어떤 값을 가지던 나는 내 오더값을 가지려 할때 true- canvas.overrideSorting = true;
- 팝업 UI의 경우 canvas.sortingOrder를
_order
로 세팅하고_order
증가시키기 - 고정 UI의 경우 canvas.sortingOrder 값을 0 으로 세팅
public T ShowSceneUI<T>(string name = null) where T : UI_Scene
{
if (string.IsNullOrEmpty(name))
name = typeof(T).Name;
GameObject go = Managers.Resource.Instantiate($"UI/Scene/{name}");
T sceneUI = Util.GetOrAddComponent<T>(go);
_sceneUI = sceneUI;
go.transform.SetParent(Root.transform);
return sceneUI;
}
public T ShowPopupUI<T>(string name = null) where T : UI_Popup
{
if (string.IsNullOrEmpty(name)) // 이름을 안받았다면 T로 ㄱㄱ
name = typeof(T).Name;
GameObject go = Managers.Resource.Instantiate($"UI/Popup/{name}");
T popup = Util.GetOrAddComponent<T>(go);
_popupStack.Push(popup);
go.transform.SetParent(Root.transform);
return popup;
}
캔버스 프리팹 생성하기
- 고정 UI 캔버스 프리팹 생성 ShowSceneUI
T
는 📜UI_Scene 자식들만 가능- 프리팹을 Instantiate으로 생성하고
_sceneUI
에 바인딩 후 이를 리턴 Root
프로퍼티를 통해@UI_Root
의 자식으로 넣어줌
- 팝업 UI 캔버스 프리팹 생성 ShowPopupUI
T
는 📜UI_PopUp 자식들만 가능- 프리팹을 Instantiate으로 생성하고
popup
에 바인딩 후 스택에 추가. 그리고 이를 리턴 Root
프로퍼티를 통해@UI_Root
의 자식으로 넣어줌
_order++
처리를 ShowPopupUI 에서 안하고 SetCanvas에서 해준 이유는, 캔버스 프리팹을 통해 생성되는 경우(ShowPopupUI 사용해서) 말고! 이미 게임 시작전부터 static 하게 존재하고 있던, 프리팹으로부터 생성된게 아닌 팝업 UI일 경우도 있을 수 있기 때문이다. 그런 경우엔 ShowPopupUI를 거치지 않기 때문에 sort order 관리가 안될 것이다. 그래서 SetCanvas에서 해준 것!
public void ClosePopupUI(UI_Popup popup) // 안전 차원
{
if (_popupStack.Count == 0) // 비어있는 스택이라면 삭제 불가
return;
if (_popupStack.Peek() != popup)
{
Debug.Log("Close Popup Failed!"); // 스택의 가장 위에있는 Peek() 것만 삭제할 수 잇기 때문에 popup이 Peek()가 아니면 삭제 못함
return;
}
ClosePopupUI();
}
public void ClosePopupUI()
{
if (_popupStack.Count == 0)
return;
UI_Popup popup = _popupStack.Pop();
Managers.Resource.Destroy(popup.gameObject);
popup = null;
_order--; // order 줄이기
}
public void CloseAllPopupUI()
{
while (_popupStack.Count > 0)
ClosePopupUI();
}
}
팝업은 Close 시킬 함수가 필요하다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기