콘텐츠로 이동

Unity 에디터 커스텀 윈도우

using UnityEditor;
using UnityEngine;
public class MyToolWindow : EditorWindow {
[MenuItem("Tools/My Tool")]
public static void ShowWindow() {
GetWindow<MyToolWindow>("My Tool");
}
string _searchQuery = "";
Vector2 _scroll;
void OnGUI() {
EditorGUILayout.LabelField("My Tool", EditorStyles.boldLabel);
_searchQuery = EditorGUILayout.TextField("검색", _searchQuery);
_scroll = EditorGUILayout.BeginScrollView(_scroll);
// 콘텐츠
EditorGUILayout.EndScrollView();
if (GUILayout.Button("실행")) Execute();
}
void Execute() { /* ... */ }
}

직접 필드를 수정하면 Undo가 동작하지 않습니다. SerializedObject를 경유하면 Undo/Redo, Prefab Override가 자동 지원됩니다.

[CustomEditor(typeof(EnemyData))]
public class EnemyDataEditor : Editor {
SerializedProperty _hp;
SerializedProperty _speed;
void OnEnable() {
_hp = serializedObject.FindProperty("hp");
_speed = serializedObject.FindProperty("speed");
}
public override void OnInspectorGUI() {
serializedObject.Update(); // 최신값 로드
EditorGUILayout.PropertyField(_hp, new GUIContent("체력"));
EditorGUILayout.PropertyField(_speed, new GUIContent("속도"));
if (serializedObject.hasModifiedProperties)
serializedObject.ApplyModifiedProperties(); // 변경 커밋 + Undo 등록
}
}

PropertyDrawer로 인스펙터 커스터마이징

섹션 제목: “PropertyDrawer로 인스펙터 커스터마이징”
[System.Serializable]
public struct Range { public float Min; public float Max; }
[CustomPropertyDrawer(typeof(Range))]
public class RangeDrawer : PropertyDrawer {
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label) {
EditorGUI.BeginProperty(pos, label, prop);
pos = EditorGUI.PrefixLabel(pos, label);
float half = pos.width / 2f - 2f;
var minProp = prop.FindPropertyRelative("Min");
var maxProp = prop.FindPropertyRelative("Max");
EditorGUI.PropertyField(new Rect(pos.x, pos.y, half, pos.height), minProp, GUIContent.none);
EditorGUI.PropertyField(new Rect(pos.x+half+4, pos.y, half, pos.height), maxProp, GUIContent.none);
EditorGUI.EndProperty();
}
}

Unity 2021+에서 권장되는 방식으로 UXML + USS로 레이아웃을 구성합니다.

public class MyToolWindow : EditorWindow {
[MenuItem("Tools/My Tool (UIToolkit)")]
public static void ShowWindow() => GetWindow<MyToolWindow>();
public void CreateGUI() {
// UXML 로드
var uxml = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
"Assets/Editor/MyTool.uxml");
uxml.CloneTree(rootVisualElement);
// 요소 참조 및 이벤트 등록
var btn = rootVisualElement.Q<Button>("execute-btn");
btn.clicked += Execute;
var field = rootVisualElement.Q<TextField>("search-field");
field.RegisterValueChangedCallback(e => OnSearchChanged(e.newValue));
}
void Execute() { }
void OnSearchChanged(string query) { }
}
// 씬의 특정 컴포넌트 전체 검색
static T[] FindAllInScene<T>() where T : Component =>
Object.FindObjectsByType<T>(FindObjectsSortMode.None);
// 에셋 생성
static T CreateAsset<T>(string path) where T : ScriptableObject {
var asset = ScriptableObject.CreateInstance<T>();
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssets();
return asset;
}
// 선택된 오브젝트에 컴포넌트 일괄 추가
[MenuItem("Tools/Add Rigidbody to Selection")]
static void AddRigidbody() {
foreach (var go in Selection.gameObjects) {
Undo.AddComponent<Rigidbody>(go);
}
}
const string PrefKey = "MyTool_SearchQuery";
void OnEnable() => _searchQuery = EditorPrefs.GetString(PrefKey, "");
void OnDisable() => EditorPrefs.SetString(PrefKey, _searchQuery);
  • EditorWindow로 독립 윈도우, Editor/PropertyDrawer로 인스펙터 커스텀
  • SerializedObject + ApplyModifiedProperties로 Undo/Prefab Override 자동 지원
  • UI Toolkit(UIElements)이 Unity 2021+에서 권장 방식
  • EditorPrefs로 개발자별 설정 유지
  • Undo.AddComponent, Undo.RecordObject로 에디터 조작에 Undo 지원