[TIL] 유니티 커스텀 메뉴
📕학습 개요
커스텀 에디터란? -말 그대로 유니티 인스펙터 창을 커스텀하는 기능이며, UI를 더 직관적으로 구성 가능하고, 개발 중 반복 작업을 줄이고 생산성을 향상시키는 효과를 가진다. 또한, 디자이너와 팀원이 쉽게 데이터를 편집 가능하다는 장점이 있으며 툴 제작이나 에디터 확장에 유용하게 활용된다.
📖학습 내용
커스텀 에디터 제작에 사용되는 클래스
- EditorGUILayout
- EditorGUI
- GUILayout
- GUI
주요 UI 항목
| 항목 | 설명 |
|---|---|
| LabelField | 텍스트 라벨 표시 |
| TextField | 한 줄 문자열 입력 |
| TextArea | 여러 줄 문자열 입력 |
| IntField | 정수 입력 |
| FloatField | 실수 입력 |
| Space | 여백 삽입 |
| HelpBox | 설명이나 경고 메시지 박스 |
| Button | 버튼 생성 및 클릭 이벤트 처리 |
| HorizontalScope / VerticalScope | UI 배치 정렬 용도 |
| Toggle | 체크박스 (bool 값) |
| Slider | 슬라이더 UI (min~max 값 사이 float) |
| Vector2Field / Vector3Field | 벡터 값 입력 |
| ObjectField | 오브젝트(에셋, GameObject 등) 참조 설정 |
| EnumPopup | Enum 타입 선택 드롭다운 |
| Popup | 문자열 배열 기반 드롭다운 |
| ColorField | 색상 선택 |
| CurveField | 애니메이션 커브 입력 |
| RectField | Rect 영역 입력 |
| BoundsField | Bounds 영역 입력 |
| Foldout | 접이식 섹션 UI |
실제 활용 예시
1. 플레이어 스탯 에디터
public class PlayerStats : MonoBehaviour
{
public int hp = 100;
public int mp = 100;
public bool isGodMode = false;
public void InitPlayerData()
{
hp = 100;
mp = 100;
isGodMode = false;
}
}
[CustomEditor(typeof(PlayerStats))]
public class PlayerStatsEditor : Editor
{
//인스펙터에 GUI를 커스탐하기 위한 기본 메소드
public override void OnInspectorGUI()
{
var playerStats = (PlayerStats)target;
EditorGUILayout.Space();
EditorGUILayout.HelpBox("주인공 캐릭터 스탯", MessageType.Info);
EditorGUILayout.Space();
//입력 필드
playerStats.hp = EditorGUILayout.IntSlider("생명력", playerStats.hp, 0, 100);
playerStats.mp = EditorGUILayout.IntSlider("마나", playerStats.mp, 0, 100);
EditorGUILayout.BeginHorizontal();
//무적 모드 토글 버튼
if(GUILayout.Button(playerStats.isGodMode ? "일반 모드로 전환" : "무적 모드로 전환"))
{
playerStats.isGodMode = !playerStats.isGodMode;
}
//플레이어 데이터 초기화
if(GUILayout.Button("데이터 초기화"))
{
playerStats.InitPlayerData();
}
EditorGUILayout.EndHorizontal();
}
}
저번 팀 프로젝트를 할 때 내가 플레이어 조작 부분을 맡았는데, 팀원들로부터 플레이어의 기본 스탯을 어떻게 조절하는지에 대한 질문을 많이 받았다. 이런 식으로 직관적인 메뉴를 만들어서 보여준다면, 협업 과정에서 굉장히 편리할 수 있겠다는 생각이 들었다.
2. 게임매니저 에디터
[CustomEditor(typeof(GameManager))]
public class GameManagerEditor :Editor
{
public override void OnInspectorGUI()
{
var manager = target as GameManager;
EditorGUILayout.ObjectField("GameManager", MonoScript.FromMonoBehaviour(manager), typeof(MonoScript), false);
EditorGUILayout.BeginHorizontal();
if(GUILayout.Button("적 생성"))
{
manager.SpawnEnemy();
}
if(GUILayout.Button("적 삭제"))
{
var enemies = GameObject.FindGameObjectsWithTag("Enemy");
foreach(var enemy in enemies)
{
DestroyImmediate(enemy);
}
}
EditorGUILayout.EndHorizontal();
}
}
게임을 테스트 하는 과정에서 쉽게 테스트 하기 위해 일부러 특정 수치를 크게 높여놓고는 했는데, 이런 식으로 테스트 전용 버튼을 만들어놓으면 게임 테스트 과정에서 굉장히 편리할 것 같다.
3. 아이템 데이터 생성기
public class ItemCreator : EditorWindow
{
private string itemName = "New Item";
private ItemType itemType = ItemType.Weapon;
private int quantity = 1;
private bool isMultiple = false;
[MenuItem("Window/Item Creator")]
private static void ShowWindow()
{
GetWindow<ItemCreator>("아이템 생성기");
}
private void OnGUI()
{
itemName = EditorGUILayout.TextField("아이템 명", itemName);
itemType = (ItemType)EditorGUILayout.EnumPopup("아이템 종류", itemType);
quantity = EditorGUILayout.IntField("수량", quantity);
isMultiple = EditorGUILayout.Toggle("복수 보유", isMultiple);
if(GUILayout.Button("아이템 생성"))
{
ItemData data = ScriptableObject.CreateInstance<ItemData>();
data.itemName = itemName;
data.itemType = itemType;
data.quantity = quantity;
data.isMultiple = isMultiple;
AssetDatabase.CreateAsset(data, $"Assets/{itemName}.asset");
AssetDatabase.SaveAssets();
}
}
}
이런 식으로 데이터 생성기를 따로 만들어놓는다면 유니티를 잘 다룰 줄 모르는 사람들도 쉽게 데이터를 생성할 수 있을 것 같다. 유니티를 다룰 줄 아는 사람 입장에서도 윈도우 창에서 에디터에 접근하여 생성하는 식이 조금이라도 편리할 것이라 생각한다.
🏁오늘 배운 내용 정리
유니티의 커스텀 메뉴를 사용하면 게임 내 데이터에 더욱 쉽고 편리하게 접근 할 수 있다. 사실 코드를 직접 짠 개발자 입장에서는 인스펙터 창에 뜨는 정보가 뭘 의미하는지 쉽게 알 수 있겠지만, 다른 개발자들 입장에서는 그렇지 않다. 하지만 커스템 메뉴를 통해 정보를 직관적으로 전달한다면 협업 과정에서의 효율이 많이 증진될 것 같다. 세상에 존재하는 모든 것은 일단 보기 좋아서 나쁠 건 없으니까…
댓글남기기