using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem.UI; using UnityEngine.UI; /// /// uGUI 조각을 코드로 만드는 공용 부품. 채팅창과 설정창이 같은 것을 쓴다. /// /// 에셋(프리팹/스프라이트/폰트)을 하나도 만들지 않는 것이 이 프로젝트의 방침이다. /// 이유는 ChatUiTheme 에 적어뒀다. /// public static class ChatUiBuilder { /// /// 씬에 EventSystem 이 없으면 만든다. 런타임 UI 를 쓰는 쪽은 모두 이걸 먼저 부른다. /// /// Active Input Handling 이 신규 Input System 전용이므로 모듈은 /// InputSystemUIInputModule 이어야 한다. StandaloneInputModule 은 레거시 /// UnityEngine.Input 을 쓰기 때문에 이 설정에서 예외를 던진다. /// public static void EnsureEventSystem() { var existing = Object.FindFirstObjectByType(); if (existing == null) { var go = new GameObject("EventSystem"); existing = go.AddComponent(); var module = go.AddComponent(); // 런타임에 붙이면 액션 에셋이 비어 있어 아무 입력도 받지 못한다. if (module.actionsAsset == null) module.AssignDefaultActions(); } // InputField 가 IME 상태를 물을 때 레거시 Input 으로 새지 않게 막는다. // BaseInputModule 은 BaseInput 을 "상속한" 컴포넌트를 기본값으로 고르지 않으므로 // inputOverride 에 직접 넣어야 한다. var baseModule = existing.GetComponent(); if (baseModule != null && baseModule.inputOverride == null) { var safeInput = existing.GetComponent(); if (safeInput == null) safeInput = existing.gameObject.AddComponent(); baseModule.inputOverride = safeInput; } } public static RectTransform NewRect(string name, Transform parent) { var go = new GameObject(name, typeof(RectTransform)); var rect = go.GetComponent(); rect.SetParent(parent, false); return rect; } /// 부모를 가득 채우도록 늘린다. public static void Stretch(RectTransform rect, float horizontal = 0f, float vertical = 0f) { rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = new Vector2(horizontal, vertical); rect.offsetMax = new Vector2(-horizontal, -vertical); } public static Image NewImage(string name, Transform parent, Sprite sprite, Color color) { var rect = NewRect(name, parent); var image = rect.gameObject.AddComponent(); image.sprite = sprite; if (sprite != null) image.type = Image.Type.Sliced; image.color = color; return image; } public static Text NewText(string name, Transform parent, string value, int fontSize, Color color) { var rect = NewRect(name, parent); var text = rect.gameObject.AddComponent(); text.font = ChatUiTheme.Font; text.fontSize = fontSize; text.color = color; text.text = value; text.supportRichText = false; // 글자가 스크롤 드래그나 버튼 클릭을 가로채지 않게 한다. text.raycastTarget = false; return text; } public static Button NewButton(string name, Transform parent, string label, int fontSize, Color background, Color foreground) { var image = NewImage(name, parent, ChatUiTheme.RoundedSmall, background); var rect = image.rectTransform; var button = rect.gameObject.AddComponent