■ Editor - 커스텀 인스펙터
public class SizeController : MonoBehaviour
{
// Do Something...
}
유니티에서 MonoBehaviour를 상속받는 스크립트는 게임 오브젝트에 부착할 수 있으며, 부착 시 모든 public 필드와 [SerializeField] 변수를 인스펙터에 자동으로 노출한다.
하지만 이러한 기본 기능 외에도, 버튼을 눌러 특정 함수를 실행하거나, 에디터 모드(Edit Mode)에서도 실시간으로 값을 반영하고 조작하고 싶을 때가 있다.
- 이럴 때 CustomEditor를 사용하면 원하는 형태로 인스펙터를 자유롭게 커스터마이징 할 수 있다.
1. Custom Editor 생성
public class SizeController : MonoBehaviour
{
[SerializeField] private GameObject obj;
[SerializeField] private Vector3 scale;
public void ChangeScale()
{
obj.transform.localScale = scale;
}
private void Update()
{
ChangeScale();
}
}
위 스크립트는 인스펙터에서 값을 수정하면 해당 오브젝트의 크기를 바꾸는 아주 단순한 스크립트이다.
다만, 이 스크립트는 Updata()를 통해 실행되므로 오직 Play Mode에서만 동작하며, 에디터 모드로 돌아오면 변경한 값이 실제 오브젝트에 반영되지 않는다.
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(SizeController))]
public class SizeControlEditor : Editor
{
private SerializedProperty _scaleProp;
private void OnEnable()
{
_scaleProp = serializedObject.FindProperty("scale");
}
public override void OnInspectorGUI()
{
var sizeController = (SizeController)target;
// 기존 인스펙터를 그리는 함수
DrawDefaultInspector();
if (GUILayout.Button("Apply"))
{
sizeController.ChangeScale();
}
}
}
CustomEditor는 Unity의 Editor 클래스를 상속받아 작성하며, 인스펙터를 직접 커스터마이즈 할 수 있도록 해준다.
이러한 스크립트는 반드시 Editor 전용 폴더(예 : Assets/Editor) 내에 위치해야 한다.
- UnityEditor 네임스페이스는 런타임이 아닌 에디터 전용 API를 포함하므로, Unity의 빌드 대상에는 포함되지 않아야 한다. Unity는 자동으로 Editor 폴더 내 스크립트를 제외하기 때문에 커스텀 에디터 스크립트는 항상 Editor 폴더에 작성해야 한다.
2. Editor 추상 클래스
커스텀 에디터를 구현하기 위해선 Editor 추상 클래스를 상속받아야 한다. 이 클래스의 구성 요소는 아래와 같다.
항목 | 설명 |
OnEnable() | 인스펙터 창을 클릭하면 처음으로 한번 호출되는 함수. |
OnInspectorGUI() | 인스펙터 창에 어떤 UI 요소를 보여줄지 정의하며, 인스펙터가 그려질 때마다 자동으로 호출된다. |
DrawDefaultInspector() | 기존 인스펙터 UI를 출력하는 함수. |
1. target 프로퍼티
target은 현재 커스텀 에디터가 편집 중인 컴포넌트 인스턴스를 가리킨다. 즉, 오브젝트 자체가 아니라 그 오브젝트의 붙은 스크립트 컴포넌트를 참조한다.
[CustomEditor(typeof(SizeController))]
위와 같이 CustomEditor 어트리뷰트로 대상 타입을 지정하면, Unity는 해당 에디터가 SizeController용이라는 것을 인식하고, 해당 컴포넌트를 target에 자동으로 할당한다.
- 따라서 new나 GetComponent<>() 호출 없이 사용할 수 있다.
- target은 UnityEngin.Object 타입이므로, 사용 시 명시적 캐스팅이 필요하다.
public override void OnInspectorGUI()
{
var sizeController = (SizeController)target;
DrawDefaultInspector();
if (GUILayout.Button("Apply"))
{
sizeController.ChangeScale();
}
}
위와 같이 target을 통해 연결된 컴포넌트 인스턴스를 가져오면, 그 내부에 정의된 함수를 직접 호출하는 것도 가능하다.
- 버튼을 만들고 클릭하면, ChangeScale() 함수가 실행되어 인스펙터에서 설정한 값을 적용할 수 있다.
2. SerializedProperty
SerializedProperty는 직렬화된 데이터를 안전하게 조작할 수 있도록 감싼 객체이다.
직렬화된 필드를 직접 수정하는 대신, SerializedProperty를 통해 간접적으로 접근할 수 있게 함으로써 Undo/Redo, 멀티 오브젝트 편집, 프리팹 동기화 같은 기능을 안전하게 처리할 수 있다.
[CustomEditor(typeof(SizeController))]
public class SizeControlEditor : Editor
{
private SerializedProperty _scaleProp;
private void OnEnable()
{
_scaleProp = serializedObject.FindProperty("scale");
}
public override void OnInspectorGUI()
{
var sizeController = (SizeController)target;
DrawDefaultInspector();
// 1. 현재 에디터 대상 오브젝트(target)의 최신 값을 직렬화 시스템에 반영.
serializedObject.Update();
// SerializedProperty를 통한 접근
if (GUILayout.Button("Apply(SerializedProperty)"))
{
// 2. SerializedProperty 값 설정
_scaleProp.vector3Value = new Vector3(3, 3, 3);
}
// 3. 변경 내용 적용 (쓰기 완료)
serializedObject.ApplyModifiedProperties();
}
}
▶ serializedObject.FindProperty("이름")
직렬화된 필드를 SerializedProperty로 가져온다.
▶ serializedObject.Update()
직렬화 시스템의 내부 데이터를 최신 상태로 동기화한다.
인스펙터에서 scale 값을 수정하더라도, 이 값은 바로 SerializedProperty에 반영되지 않기 때문에, 수정된 내용을 정확하게 반영하려면 먼저 Update() 함수를 호출해야 한다.
▶serializedObject.ApplyModifiedProperties()
변경한 내용을 실제 오브젝트에 적용한다.
■ GUILayout
GUILayout 은 UnityEditor에서 제공하는 자동 레이아웃 기반 UI 그리기 도구이다.
- 버튼, 텍스트, 입력 필드 등 다양한 GUI 요소를 좌표 계산 없이 자동으로 배치해 준다.
- OnInspectorGUI()나 OnGUI() 내부에서 사용하여 인스펙터나 커스텀 에디터 창의 UI를 구성할 수 있다.
함수 | 설명 |
GUILayout.Label("텍스트") | 단순한 텍스트 출력 |
GUILayout.Button("클릭") | 버튼 출력 (클릭 여부 반환) |
GUILayout.TextField("내용") | 텍스트 입력 필드 출력 |
GUILayout.Toggle(bool, "이름") | 체크박스 |
GUILayout.Space(픽셀) | 수직 여백 추가 |
GUILayout.BeginVertical() / EndVertical() | 위아래 정렬 그룹 시작/끝 |
GUILayout.BeginHorizontal() / EndHorizontal() | 좌우 정렬 그룹 시작/끝 |
이 함수들을 사용해 인스텍터 창을 직관적이고 자유롭게 구성할 수 있으며 아래 Unity 공식 문서를 참고하면 더 많은 종류의 함수를 사용할 수 있다.
'Unity,C# > Unity 정보' 카테고리의 다른 글
[Unity, C#] ScriptableObject - 스크립터블 오브젝트 (4) | 2025.08.02 |
---|---|
[Unity, C#] EditorWindow - 커스텀 에디터 윈도우 (1) | 2025.08.02 |
[C#] LINQ(Language Integrated Query) (1) | 2025.06.27 |
[Unity] Coroutine(코루틴) 파헤치기 (4) | 2025.05.30 |