JJB's gloomy DEV

[Unity3D/Editor] 커스텀에디터 활용기 1편 - JJB.

by JJB.

Editor에서 Inspector 커스텀

작업을 하다 보면 Inspector에서 외부로 노출하지 않아도 되는 필드나, 특정 조건에 의해 노출되는 필드를 변경하고 싶은 순간이 빈번하게 찾아옵니다. 이때 Editor 작업을 많이 해보지 않으신 분들은 당황을 하기 마련인데요.

Inspector에서 원하는 필드만 노출되도록 작업하는 방식을 말씀드리겠습니다.

 

MonoBehaviour를 상속받은 스크립트 작성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[Serializable]
public class CarInfo
{
    public int name;
    public float speed;
}

[Serializable]
public class MonsterInfo
{
    public string name;
    public int power;
    public int hp;
    public int mp;
}


public enum ObjectType
{
    CAR,
    MONSTER
}

public class ObjectInspector : MonoBehaviour
{
    // ---------------------------------------------------
	// HideInInspector 어트리뷰트를 사용해서 해당 필드를 일단 숨겨줍니다.
    // 추 후 에디터 코드에서 해당 필드를 노출시켜 줄 예정입니다.
    // ---------------------------------------------------
    [HideInInspector] [SerializeField] ObjectType _objectType;
    [HideInInspector] [SerializeField] private CarInfo _carInfo;
    [HideInInspector] [SerializeField] private MonsterInfo _monsterInfo;
}

ObjectInspector라는 클래스를 간단하게 작성해 보았습니다.

저는 여기서 '_objectType' 필드에 에 따라 '_carInfo' 혹은 '_monsterInfo' 필드가 Inspector에 노출될 수 있도록 작업 예정입니다.

그리고 위의 주석에 적어 놓은 것과 같이 해당 클래스에서는 노출할 필드에 'HideInInspector' Attribute를 일단 추가해줍니다.

 

Editor 스크립트 작성

using System;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

[CustomEditor(typeof(ObjectInspector))]
public class ObjectInspectorEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        
        serializedObject.Update();
        
        // _objectType 필드를 가져옵니다.
        var objectType = (ObjectType)serializedObject.FindProperty("_objectType").intValue;
        // _objectType 필드를 Inspector에 노출 시켜줍니다.
        EditorGUILayout.PropertyField(serializedObject.FindProperty("_objectType"));
        
        // Inspector에서 ObjectType Enum을 변경하게 되면 해당 타입에 맞게 노출시켜줄 필드를 정의해줍니다.
        switch (objectType)
        {
            case ObjectType.CAR:
            {
            	// CarInfo는 클래스이므로 '_carInfo.name' 형태로 클래스 내부에 접근할 수 있습니다.
                // 프로퍼티를 가져옴과 동시에 Inspector에 노출시켜 줍니다.
                EditorGUILayout.PropertyField(serializedObject.FindProperty("_carInfo.name"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("_carInfo.speed"));
            }
                break;

            case ObjectType.MONSTER:
            {
            	// MonsterInfo는 클래스이므로 '_monsterInfo.name' 형태로 클래스 내부에 접근할 수 있습니다.
                // 프로퍼티를 가져옴과 동시에 Inspector에 노출시켜 줍니다.
                EditorGUILayout.PropertyField(serializedObject.FindProperty("_monsterInfo.name"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("_monsterInfo.power"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("_monsterInfo.hp"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("_monsterInfo.mp"));
            }
                break;
        }
        
        // 변경된 프로퍼티를 저장해줍니다.
        serializedObject.ApplyModifiedProperties();
    }
}

'serializedObject' , 'serializedProperty'를 활용하여 'ObjectType'에 따라 노출되는 필드를 작업하였습니다.

serializedObject의 경우 직렬화된 오브젝트를 찾아줍니다.

+) https://docs.unity3d.com/ScriptReference/Editor-serializedObject.html - Unity 공식문서

 

여기에선 클래스 상단 '[CustomEditor(typeof(ObjectInspector))]'에 작성한 ObjectInspector 컴포넌트가 붙어있는 오브젝트가 되겠죠?  그리고 'serializedObject.FindProperty( '필드명' )' 형태로 SerializeField 필드를 찾을 수 있습니다.

'SerializedProperty' 클래스 내부에는 여러 가지 타입을 get, set 형태로 접근할 수 있도록 제공을 하고 있는데요. 타입에 맞는 값을 넣고 빼고를 자유롭게 해 주시면 됩니다.

 

Car Type
MonsterType

 

마치며

Editor Class의 경우 항상 Editor폴더를 만들어 내부에서 관리하는 습관을 가지는 게 좋습니다. 그리고 Editor Class 작성을 완료했다면 빌드를 한번 해보시는 걸 꼭 추천드립니다.

 

 

'Unity3D' 카테고리의 다른 글

[Unity3D/UniTask] UniTask 비동기 로딩 처리 방법 - JJB.  (0) 2022.07.02

블로그의 정보

JJB's gloomy DEV

JJB.

활동하기