본문 바로가기
유니티

Custom Editor

by JunHDev 2025. 8. 30.

서론


- 프로젝트 진행 중 파티클 시스템을 사용하는데 SortLayerID를 하나씩 세팅을 해줘야하는 번거로움이 있었다.

해당 번거로움을 개선하기 위해서 Awake에 Effect라는 SortLayerID를 부여하도록 했지만 이번에 기획자분도 새롭게 참여를 할 것 같아 가시성이 좋게 진행하는 방법이 뭐가 있을까 싶었다.

그렇게 찾은 기능이 Custom Editor기능이다.  

 

 

 

 

Custom Editor


커스텀 에디터의 목적

 

1. 인스펙터 UI 제어

 * 유니티 기본 인스펙터는 [SerializeField]된 필드를 자동으로 나열해 보여준다.

 * 하지만 일부 데이터는 슬라이더, 드롭다운,색상 선택기 등으로 보여주는게 훨씬 직관적이다.

EX) SortinLayerID는 단순 int입력으로 값을 지정했다면 커스텀 에디터를 통해 SortingLayer 목록 드랍다운으로

보여준다.

 

2. 작업 효율성 향상

 * 에디터에 버튼이나 툴 패널을 추가해서 반복적인 작업을 자동화할 수 있다.

EX) NavMesh 다시 굽기 버튼, Prefab 초기화 등등

 

3. 데이터 검증 및 제약

 * 잘못된 값을 입력하지 못하게 막거나, 입력 시 자동으로 보정할 수 있다.

 

4. 시각화 / 디버깅

 * SceneView와 Inspector를 연결해서 데이터 시각화를 할 수 있다.

EX) AI의 시야 범위를 SceneView에 원으로 그려주기

 

결론


- 커스텀 데이터의 목적은 "개발 편의성과 생산성 향상, 잘못된 데이터 입력 방지, 디버깅과 시각화 보조가 핵심"이다.

 

 

연습


*커스텀 에디터를 제작하기전에 내가 사용할 클래스를 미리 제작해야한다.

using UnityEngine;

/// <summary>
/// 부모 오브젝트 포함 모든 자식의 ParticleSystemRenderer의
/// Sorting Layer를 지정된 레이어로 자동 변경하는 스크립트.
/// </summary>
public class ParticleSortingLayerSetter : MonoBehaviour
{
    [Tooltip("적용할 Sorting Layer")]
    [SerializeField] private string targetSortingLayer = "Default";

    private void Awake()
    {
        ApplySortingLayer();
    }

    private void ApplySortingLayer()
    {
        int layerId = SortingLayer.NameToID(targetSortingLayer);

        if (layerId == 0 && targetSortingLayer != "Default")
        {
            Debug.LogWarning($"[ParticleSortingLayerSetter] 지정한 SortingLayer '{targetSortingLayer}'가 존재하지 않습니다.");
            return;
        }

        ParticleSystemRenderer[] renderers = GetComponentsInChildren<ParticleSystemRenderer>(true);

        foreach (var psr in renderers)
        {
            psr.sortingLayerID = layerId;
        }

        Debug.Log($"[ParticleSortingLayerSetter] {renderers.Length}개의 파티클 SortingLayer를 '{targetSortingLayer}'로 변경 완료!");
    }
}

 

해당 스크립트를 객체에 넣어주면 이미지처럼 나온다. 

사용하는데 지장은 없겠지만 여러 오브젝트를 세팅하기에는 번거로움이 있다.

 

 

커스텀 에디터 

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ParticleSortingLayerSetter))]
public class ParticleSortingLayerSetterEditor : Editor
{
    public override void OnInspectorGUI()
    {
        ParticleSortingLayerSetter script = (ParticleSortingLayerSetter)target;

        // 현재 Sorting Layer 목록 가져오기 (안전한 방식)
        string[] sortingLayers = SortingLayer.layers != null ? new string[SortingLayer.layers.Length] : new string[0];
        for (int i = 0; i < sortingLayers.Length; i++)
        {
            sortingLayers[i] = SortingLayer.layers[i].name;
        }

        // 현재 값 가져오기
        string currentLayer = GetPrivateField<string>(script, "targetSortingLayer");

        int currentIndex = Mathf.Max(0, System.Array.IndexOf(sortingLayers, currentLayer));

        // 드롭다운
        int newIndex = EditorGUILayout.Popup("Target Sorting Layer", currentIndex, sortingLayers);

        if (sortingLayers.Length > 0 && newIndex >= 0 && newIndex < sortingLayers.Length)
        {
            string newLayer = sortingLayers[newIndex];
            if (newLayer != currentLayer)
            {
                Undo.RecordObject(script, "Change Sorting Layer");
                SetPrivateField(script, "targetSortingLayer", newLayer);
                EditorUtility.SetDirty(script);
            }
        }

        // 나머지 인스펙터 기본 그리기
        DrawDefaultInspector();
    }

    // private 필드 접근용 유틸
    private T GetPrivateField<T>(object obj, string fieldName)
    {
        var field = obj.GetType().GetField(fieldName,
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        return (T)field.GetValue(obj);
    }

    private void SetPrivateField<T>(object obj, string fieldName, T value)
    {
        var field = obj.GetType().GetField(fieldName,
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        field.SetValue(obj, value);
    }
}

 

여기서 주목해야할 클래스가 있는데

EditorGUILayout이다. UI 그리기 함수 집합의 기능을 가지고 있으며 커스텀 에디터를 제작할때 반 필수적인

클래스이다.

https://docs.unity3d.com/ScriptReference/EditorGUILayout.html?utm_source=chatgpt.com

 

 

 

이미지처럼 드랍다운이 생성되었다!

 

 

 

또는 해당 이미지처럼 직렬화 없이 인스펙터에서 데이터 확인이 가능하게 제작할수있다.

'유니티' 카테고리의 다른 글

유니티 자동화 툴 만들기<프로젝트 에셋 관련 기능 정리>  (0) 2025.11.01
오디오 믹서 (Aduio Mixer)  (1) 2025.09.14
스크립팅 백엔드  (2) 2025.03.30
RectTransformUtility  (3) 2025.03.19
RectTransformUntility에 대해서  (17) 2025.01.07