美文网首页
UnityEditor中使用静态变量

UnityEditor中使用静态变量

作者: e196efe3d7df | 来源:发表于2019-08-20 19:05 被阅读0次

    接到一个需求,在菜单栏中添加一个按钮,用来快速运行入口场景,并且在场景运行结束后,回到上一个正在编辑的场景。第一个功能:快速运行入口场景,已经实现。
    本来以为第二个功能会非常简单,不就是保存一下上一个场景路径,场景运行结束后,加载上一个场景不就好了,但是在实际运行过程中出现了很大问题,这个问题在2017和2018的版本中都会产生,就是在编辑器代码定义变量,会多次被重置!原因是,自定义的类,会被多次构造,每次构造类里面的变量就会被重置,最致命的是,向引擎中注册的委托都会被清理掉!不知道是官方故意如此,还是一个bug!
    先展示一下,此bug如何重现的。

    public class StartMain
    {
        static string lastOpenSceneName;
        static string lastOpenScenePath;
    
        [InitializeOnLoadMethod]
        static void Init()
        {
            EditorApplication.playModeStateChanged += HandleOnPlayModeChanged;
        }
        [MenuItem("Tools/StartMain", false, 1)]
        static void StartMainScene()
        {
            if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().isDirty)
            {
                if (EditorUtility.DisplayDialog("提示", "是否保存当前场景", "确定", "取消"))
                {
                    EditorSceneManager.SaveOpenScenes();
                }
            }
            lastOpenSceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name
            lastOpenScenePath = UnityEngine.SceneManagement.SceneManager.GetActiveScene().path;
            if (!lastOpenSceneName.Equals("Main"))
            {
                EditorSceneManager.OpenScene("Assets/GameAssets/Map/Main.unity");
            }
            EditorApplication.ExecuteMenuItem("Edit/Play");
        }
    
        static void HandleOnPlayModeChanged(PlayModeStateChange playMode)
        {
            if (playMode.Equals(PlayModeStateChange.ExitingPlayMode))
            {
                EditorSceneManager.OpenScene(lastOpenScenePath);
                lastOpenScenePath = null;
            }
        }
    
    }
    

    以上代码看似没有问题,但在运行过程中,Init()函数会被执行两次,第一次在保存代码后,第二次在开始运行场景时。当点击StartMain时,场景还没有运行,会给lastOpenScenePath赋值,但是当场景运行时又再一次执行了Init()函数,这时lastOpenScenePath重置为null,气不气!
    可能会有人想,不用[InitializeOnLoadMethod]这个标签,我用[InitializeOnLoad][RuntimeInitializeOnLoadMethod],我已经尝试过了,没用!那干脆不用构造函数什么的,定义这些变量后,直接在StartMainScene使用!但是依旧会被重置!甚至注册的委托也会被重置掉!
    最后实在没办法了,只能使用PlayerPrefs来保存变量值了。附上完整代码:

    using UnityEngine;
    using UnityEditor;
    using UnityEditor.SceneManagement;
    
    public class StartMain
    {
        //注:一定不要使用变量!!!构造函数会执行两次!!!
        [InitializeOnLoadMethod]
        static void Init()
        {
            EditorApplication.playModeStateChanged += HandleOnPlayModeChanged;
        }
    
    
        [MenuItem("Tools/StartMain", false, 1)]
        static void StartMainScene()
        {
            if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().isDirty)
            {
                if (EditorUtility.DisplayDialog("提示", "是否保存当前场景", "确定", "取消"))
                {
                    EditorSceneManager.SaveOpenScenes();
                }
            }
            PlayerPrefs.SetString("LastOpenScenePath", UnityEngine.SceneManagement.SceneManager.GetActiveScene().path);
            PlayerPrefs.SetString("LastOpenSceneName", UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
            if (!UnityEngine.SceneManagement.SceneManager.GetActiveScene().name.Equals("Main"))
            {
                EditorSceneManager.OpenScene("Assets/GameAssets/Map/Main.unity");
            }
            EditorApplication.ExecuteMenuItem("Edit/Play");
        }
    
        [MenuItem("Tools/StartMain", true, 1)] 
        static bool ValidStartMainScene()
        {
            return !Application.isPlaying;
        }
    
        //当退出场景时,自动打开上一个场景
        static void HandleOnPlayModeChanged(PlayModeStateChange playMode)
        {
            string lastOpenSceneName = PlayerPrefs.GetString("LastOpenSceneName", null);
            if (lastOpenSceneName.isNullOrEmpty())
            {
                return;
            }
    
            if (playMode.Equals(PlayModeStateChange.ExitingPlayMode) && !lastOpenSceneName.Equals("Main"))
            {
                PlayerPrefs.SetString("LastOpenSceneName", null);
                //需要等待 完全退出 playmode
                EditorApplication.update += UpdateWhenExiting;
            }
        }
    
        static void UpdateWhenExiting()
        {
            if (!Application.isPlaying)
            {
                string lastOpenScenePath = PlayerPrefs.GetString("LastOpenScenePath", null);
                if (!lastOpenScenePath.isNullOrEmpty())
                {
                    EditorSceneManager.OpenScene(lastOpenScenePath);
                    PlayerPrefs.SetString("LastOpenScenePath", null);
                }
                EditorApplication.update -= UpdateWhenExiting;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:UnityEditor中使用静态变量

          本文链接:https://www.haomeiwen.com/subject/wckmsctx.html