[Unity] Custom Editor (2) – RectTransform Reset



這篇利用 Decorator Editor 針對 RectTransform
再建立一個能夠重設位置、旋轉與縮放的 Custom Editor
如果不知道 Decorator Editor 的話請先看這一篇:

[Unity] Custom Editor (1) – Transform Reset
Overview

1. Transform Resetter:建立能夠儲存一組 Position、Rotation、Scale 的類別
2. Transform Inspector
3. 找出 RectTransform 的 Editor 類別名稱與屬性名稱
4. RectTransform Inspector


1. Transform Resetter:建立能夠儲存一組 Position、Rotation、Scale 的類別

由於 Transform 和 RectTransform 都擁有一組 Position、Rotation 和 Scale 的屬性
因此建立了一個儲存這些屬性的 Decorator Editor
並且修改了原本儲存方式,採用 Unity 的 JsonUtility 來轉換為 string 儲存

public abstract class TransformResetter : DecoratorEditor
{
    private const string RESET_POSITION = "RESET_POSITION";
    private const string RESET_ROTATION = "RESET_ROTATION";
    private const string RESET_SCALE = "RESET_SCALE";

    protected bool m_unFold = false;

    protected static Vector3 m_resetPosition = Vector3.zero;
    protected static Vector3 m_resetRotation = Vector3.zero;
    protected static Vector3 m_resetScale = Vector3.one;

    public TransformResetter(string name) : base(name)
    {
    }

    protected void LoadCustomValues()
    {
        if (EditorPrefs.HasKey(RESET_POSITION))
        {
            m_resetPosition = JsonUtility.FromJson<Vector3>(EditorPrefs.GetString(RESET_POSITION));
        }

        if (EditorPrefs.HasKey(RESET_ROTATION))
        {
            m_resetRotation = JsonUtility.FromJson<Vector3>(EditorPrefs.GetString(RESET_ROTATION));
        }

        if (EditorPrefs.HasKey(RESET_SCALE))
        {
            m_resetScale = JsonUtility.FromJson<Vector3>(EditorPrefs.GetString(RESET_SCALE));
        }
    }

    protected void DrawCustomValues()
    {
        string originLabel;
        if (m_resetPosition != Vector3.zero || m_resetRotation != Vector3.zero || m_resetScale != Vector3.one)
        {
            originLabel = "Set Origin [Custom]";
        }
        else
        {
            originLabel = "Set Origin [Default]";
        }

        m_unFold = EditorGUILayout.Foldout(m_unFold, originLabel);
        if (m_unFold)
        {
            EditorGUI.BeginChangeCheck();
            if (GUILayout.Button("Clear Custom Origin", EditorStyles.miniButton))
            {
                m_resetPosition = Vector3.zero;
                m_resetRotation = Vector3.zero;
                m_resetScale = Vector3.one;
                GUI.FocusControl(null);
            }

            GUI.backgroundColor = Color.white;

            m_resetPosition = EditorGUILayout.Vector3Field("Position", m_resetPosition);
            m_resetRotation = EditorGUILayout.Vector3Field("Rotation", m_resetRotation);
            m_resetScale = EditorGUILayout.Vector3Field("Scale", m_resetScale);

            if (EditorGUI.EndChangeCheck())
            {
                EditorPrefs.SetString(RESET_POSITION, EditorJsonUtility.ToJson(m_resetPosition));
                EditorPrefs.SetString(RESET_ROTATION, EditorJsonUtility.ToJson(m_resetRotation));
                EditorPrefs.SetString(RESET_SCALE, EditorJsonUtility.ToJson(m_resetScale));
            }
        }
    }
}
2. Transform Inspector

接下來修改一下原本的 Transform Inspector
改繼承自 Transform Resetter
做的事情就單純多了
按下按鈕時 把值設回 Resetter 中紀錄的值就好了

[CustomEditor(typeof(Transform)), CanEditMultipleObjects]
public class TransformInspector : TransformResetter
{
    private SerializedProperty m_position;
    private SerializedProperty m_rotation;
    private SerializedProperty m_scale;

    public TransformInspector() : base("TransformInspector")
    {
    }

    void OnEnable()
    {
        m_position = serializedObject.FindProperty("m_LocalPosition");
        m_rotation = serializedObject.FindProperty("m_LocalRotation");
        m_scale = serializedObject.FindProperty("m_LocalScale");

        LoadCustomValues();
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        EditorGUILayout.Space();

        EditorGUILayout.BeginHorizontal();
        GUI.backgroundColor = new Color(0.75f, 1, 0);

        if (GUILayout.Button("Position", EditorStyles.miniButtonLeft))
        {
            m_position.vector3Value = m_resetPosition;
            serializedObject.ApplyModifiedProperties();
            GUI.FocusControl(null);
        }
        if (GUILayout.Button("Rotation", EditorStyles.miniButtonMid))
        {
            m_rotation.quaternionValue = Quaternion.Euler(m_resetRotation);
            serializedObject.ApplyModifiedProperties();
            GUI.FocusControl(null);
        }
        if (GUILayout.Button("Scale", EditorStyles.miniButtonRight))
        {
            m_scale.vector3Value = m_resetScale;
            serializedObject.ApplyModifiedProperties();
            GUI.FocusControl(null);
        }

        EditorGUILayout.EndHorizontal();

        DrawCustomValues();
    }
}
3. 找出 RectTransform 的 Editor 類別名稱與屬性名稱

接下來要找出 RectTransform 在 Unity 中的 Editor 類別檔
叫做 RectTransformEditor
在建構式裡要塞這個名字進去

public RectTransformInspector() : base("RectTransformEditor")
{
}

不知道怎麼找的話可以看這一篇:

[Unity] 如何找到 Unity 預設的 Editor 類別名稱

由於 Transform 的位置、旋轉與縮放的成員名稱分別叫做
m_LocalPosition、m_LocalRotation 與 m_LocalScale
因此我們很容易會覺得,RectTransform 也是叫一樣的名稱

但如果使用 m_LocalPosition 這個名字
就會發現在 RectTransformEditor.cs 下是找不到的
他有的只有 m_LocalPositionZ
以及另外一個 Vector2 成員:m_AnchoredPosition
所以我們所需要的 SerializedProperty 會多一個:

m_position = serializedObject.FindProperty("m_AnchoredPosition");
m_positionZ = serializedObject.FindProperty("m_LocalPosition.z");
m_rotation = serializedObject.FindProperty("m_LocalRotation");
m_scale = serializedObject.FindProperty("m_LocalScale");

[Unity] RectTransform Reset

4. RectTransform Inspector

只要找到對應的 Property 名稱
剩下來的事情就簡單了
一樣只要在按下按鈕時把值重設就好了
以下是完整的程式碼

[CustomEditor(typeof(RectTransform)), CanEditMultipleObjects]
public class RectTransformInspector : TransformResetter
{
    SerializedProperty m_position;
    SerializedProperty m_positionZ;
    SerializedProperty m_rotation;
    SerializedProperty m_scale;

    public RectTransformInspector() : base("RectTransformEditor")
    {
    }

    void OnEnable()
    {
        m_position = serializedObject.FindProperty("m_AnchoredPosition");
        m_positionZ = serializedObject.FindProperty("m_LocalPosition.z");
        m_rotation = serializedObject.FindProperty("m_LocalRotation");
        m_scale = serializedObject.FindProperty("m_LocalScale");

        LoadCustomValues();
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        EditorGUILayout.BeginHorizontal();
        GUI.backgroundColor = new Color(0.75f, 1, 0);

        if (GUILayout.Button("Position", EditorStyles.miniButtonLeft))
        {
            m_position.vector2Value = m_resetPosition;
            m_positionZ.floatValue = m_resetPosition.z;
            serializedObject.ApplyModifiedProperties();
            GUI.FocusControl(null);
        }
        if (GUILayout.Button("Rotation", EditorStyles.miniButtonMid))
        {
            m_rotation.quaternionValue = Quaternion.Euler(m_resetRotation);
            serializedObject.ApplyModifiedProperties();
            GUI.FocusControl(null);
        }
        if (GUILayout.Button("Scale", EditorStyles.miniButtonRight))
        {
            m_scale.vector3Value = m_resetScale;
            serializedObject.ApplyModifiedProperties();
            GUI.FocusControl(null);
        }

        EditorGUILayout.EndHorizontal();

        DrawCustomValues();
    }
}

完成後,RectTransform 也同樣可以進行 Reset 囉!

Github 完整專案



歡迎您留言與分享!(Welcome for comments or sharing!)

Related Post:

Tagged on: ,