Unity Custom Inspector Value Saving

 • 

最近发现 SetDirty 不太好用,总是没办法让自定义 Inspector 里面的值序列化。然后在 https://docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html 这里发现有一段话:

NOTE: ''Prior to Unity 5.3, this was the primary method of marking objects as dirty. From 5.3 onwards, with the introduction of Multi-Scene Editing, this function should no-longer be used for modifying objects in scenes. Instead, you should use Undo.RecordObject prior to making changes to the object. This will mark the object's scene as dirty and provide an undo entry in the editor.''

看了下 Undo.RecordObject 的文档,唯一的不好是 EditorGUI.BeginChangeCheck() 和 EditorGUI.EndChangeCheck() 需要一前一后,对于继承的自定义 Custom Editor 有些难办,因此用 Action 把代码变成一个 Code Block:

Helper Code

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using System;  
#if UNITY_EDITOR

using UnityEditor;  
using UnityEditor.SceneManagement;

namespace FinGameWorksEditor.Helper  
{
    public static class FGWEditorUtility
    {   
        /// <summary>
        /// Helper Function to use the Undo In Custom Inspector
        /// </summary>
        /// <param name="guiCode">code block to write editorguilayout stuff</param>
        /// <param name="targetCode">code block to write updating target variable stuff</param>
        /// <param name="target">the target monobehavior</param>
        public static void RecordUndoBlock(Action guiCode,Action targetCode,UnityEngine.Object target)
        {
            EditorGUI.BeginChangeCheck();
            guiCode();
            if (EditorGUI.EndChangeCheck())
            {
                Undo.RecordObject(target, "Changed");
                targetCode();
            }
        }
    }
}
#endif

Usage Example

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using System.Linq;  
using UnityEngine.SceneManagement;  
using FinGameWorks.Helper;

#if UNITY_EDITOR
using UnityEditor;  
using FinGameWorksEditor;  
using FinGameWorksEditor.Helper;  
using FinGameWorks.Controller.SceneManagement;

namespace FinGameWorksEditor.Controller.SceneManagement  
{
    [CustomEditor(typeof(FGWSceneLoader), true)]
    public class FGWSceneLoaderEditor : FGWMonobehaviorEditorBase
    {
        public List<string> scenesInBuild
        {
            get
            {
                if (_scenesInBuild == null)
                {
                    _scenesInBuild = FGWSceneHelper.getAllSceneNameInBuild();
                }
                return FGWSceneHelper.getAllSceneNameInBuild();;
            }
        }
        private List<string> _scenesInBuild;

        public FGWSceneLoader loader
        {
            get { return (FGWSceneLoader)target; }
        }

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            bool loadSceneOnStart = false;
            int sceneIndexToLoad = 0;
            FGWEditorUtility.RecordUndoBlock(()=>
            {
                GUILayout.Label("Parameters",EditorStyles.boldLabel);
                loadSceneOnStart = EditorGUILayout.Toggle("Load Scene On Start", loader.loadSceneOnStart);
                sceneIndexToLoad = EditorGUILayout.Popup("Scene To Set",loader.sceneIndexToLoad,scenesInBuild.ToArray());

                GUILayout.Label("Action",EditorStyles.boldLabel);
                if (GUILayout.Button("Refresh Scene List"))
                {
                    _scenesInBuild = null;
                    foreach (var item in scenesInBuild)
                    {
                        Debug.Log(item);
                    }
                }
            },
            ()=>{
                loader.loadSceneOnStart = loadSceneOnStart;
                loader.sceneIndexToLoad = sceneIndexToLoad;
            },loader);
        }
    }

}


#endif

namespace FinGameWorks.Controller.SceneManagement  
{
    public class FGWSceneLoader : MonoBehaviour
    {
        public bool loadSceneOnStart;
        public int sceneIndexToLoad;

        void Start ()
        {
            if (loadSceneOnStart)
            {
                SceneManager.LoadScene(sceneIndexToLoad);
            }
        }

        void Update () {

        }
    }
}