호우동의 개발일지

Today :

article thumbnail

목표

오브젝트에 스크립트를 넣어 인스펙터 뷰를 커스터마이징

 


직렬화(Serialization)

- 해당 필드를 유니티가 인식할 수 있는 상태로 만드는 것

- 유니티가 처리할 수 있는 형태로 만드는 것- Inspect를 조작하기 위해선 직렬화는 필수적인 과정
-> 유니티가 직렬화할 수 있는 오브젝트를 만들어야 한다.

 


CustomEditor와 Editor

우선 커스터마이징 할 스크립트[CustomScript]를 작성한다.

public class CustomScript : MonoBehaviour
{
    public GameObject otherObject;
    public string myName;
    public int myHp;
}

커스터마이징 에디터 스크립트[CustomEditorTest]를 CustomScript와 연결한다.

 

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

// CustomEditor Attribute(속성)추가
[CustomEditor(typeof(CustomScript))] // typeof(재정의하고싶은 클래스 타입)
public class CustomEditorTest : Editor // Editor class 상속 
{
}

UnityEditor를 import 한다.

속성으로 CustomEditor을 추가하여 커스터마이징이 가능하게 했다.
상속을 MonoBehaviour에서 Editor로 변경한다.

 


CustomScript의 변수(프로퍼티) 가져오기

Inspector 창을 커스터마이징해도
결국에는 Inspector를 통해 값을 바꿀 수 있어야 한다.


즉, CustomEditorTest 스크립트로 CustomScript 프로퍼티를 가져와야 한다는 것이다.


그런데 Inspector를 조작하기 위해선 직렬화된 오브젝트를 가져와야 하기 때문에,
SerializedProperty라는 데이터 타입으로 가져올 것이다.

 

SerializedProperty

- 필드 1개를 직렬화하는데 편하게 하기 위해서 데이터 타입을 하나로 모음
- 여러 가지 데이터 타입이 SerializedProperty 클래스 안에 정의되어 있다.

정의
정의
정의

 

구현

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

// CustomEditor Attribute(속성)추가
[CustomEditor(typeof(CustomScript))] // typeof(재정의하고싶은 클래스 타입)
public class CustomEditorTest : Editor // Editor class 상속 
{
    SerializedProperty targetObjectProp;
    SerializedProperty nameProp;
    SerializedProperty hpProp;

    //Hierarchy에서 CustomScript가 있는 오브젝트를 클릭시 호출
    private void OnEnable()
    {
        //serializedObject = base class인 Editor에 있는 직렬화된 오브젝트
        //FindProperty -> 직렬화된 오브젝트에서 이름으로 프로퍼티를 찾음 -> 데이터 타입 명시x(Generic 객체)
        targetObjectProp = serializedObject.FindProperty($"{nameof(CustomScript.otherObject)}");
        nameProp = serializedObject.FindProperty($"{nameof(CustomScript.myName)}");
        hpProp = serializedObject.FindProperty($"{nameof(CustomScript.myHp)}");
    }
}

데이터 타입을 SerializedProperty로 정의했다.

이후 OnEnable()에서 FindProperty를 통해
CustomScript의 변수 이름으로 프로퍼티를 찾는다.

여기서 myName은 데이터 타입이 string 이기 때문에
SerializedProperty.stringValue에 값이 저장된다.

마찬가지로 myHp는 int형이기 때문에
SerializedProperty.intValue에 값이 저장된다.

여기서 중요한 점은 데이터 타입을 정의하지 않았기 때문에 Generic 하다. 

SerializedProperty에 CustomScript의 프로퍼티들을 직렬화해서 가져왔다.

여기서 OnEnable()은 속성으로 인해 Hierarchy 창에서
CustomScript가 있는 오브젝트 클릭할 때마다 호출된다.

 


SerializedProperty 값 변경 및 GUI 생성

public override void OnInspectorGUI()
{
    //base.OnInspectorGUI(); 재정의
    serializedObject.Update(); // 모든 프로퍼티 최신화(업데이트)

	// myHp가 500 이하일때 빨간색
    if (hpProp.intValue < 500) GUI.color = Color.red;
    // 아닐땐 초록색
    else GUI.color = Color.green;

	// 슬라이더 GUI 생성
    hpProp.intValue = EditorGUILayout.IntSlider("Hp값 ", hpProp.intValue, 0, 1000);

    EditorGUILayout.BeginVertical();
    {
        GUI.color = Color.blue;
        EditorGUILayout.PrefixLabel("이름");
        GUI.color = Color.white;
        nameProp.stringValue = EditorGUILayout.TextArea(nameProp.stringValue);
    }
    EditorGUILayout.EndVertical();

    EditorGUILayout.PropertyField(targetObjectProp);

    serializedObject.ApplyModifiedProperties();// 프로퍼티 변경사항 적용
}

위와 같이 (serializedProperty 변수이름).데이터타입 Value로 값을 변경하거나 사용한다.

 

PropertyField

해당 Property의 실제 타입에 따라 드로잉을 다르게 처리한다.

EditorGUILayout.PropertyField(targetObjectProp);

게임 오브젝트형 참조

아래와 같이 targetObjectProp안에 들어있는
otherObject의 데이터 타입인 GameObject가 나온다.

 

SerializedObject.Update

Update를 쓰는 이유

다른 곳에서 Inspector에 있는 프로퍼티의 값이 바뀌었을 수도 있다.
그렇기 때문에 프로퍼티 값을 불러오기 전에 업데이트(최신화) 해줘야 한다.


SerializedObject.ApplyModifiedProperties

- 바뀐 프로퍼티 값을 다른 곳에서도 알 수 있게끔 한다.
- 이 작업을 하지 않으면 값을 바꾸어도 적용되지 않는다.