美文网首页UnityEditorUnity编辑器开发分享Unity基础入门分享
【Unity3d编辑器从入门到精通】深入简出聊Undo

【Unity3d编辑器从入门到精通】深入简出聊Undo

作者: 霸俊流年 | 来源:发表于2017-09-28 20:08 被阅读100次

    简单演示Undo

    Undo的演示

    Undo的原理 LIFO

    原理 变色

    简单实现

    创建物体Undo.RegisterCreatedObjectUndo

        [MenuItem("Example/Create Cube")]
        static void CreateCube()
        {
            var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
            Undo.RegisterCreatedObjectUndo(cube, "Create Cube");
        }
    
    执行效果

    属性变化RecordObject/RegisterCompleteObjectUndo

        [MenuItem("Example/Random Rotate")]
        static void RandomRotate ()
        {
            var transform = Selection.activeTransform;
    
            if (transform) {
                Undo.RecordObject (transform, "Rotate " + transform.name);
                transform.rotation = Random.rotation;
            }
        }
    

    Unity又是怎么处理的呢?PropertyDiffUndoRecorder

    使用Profiler检查PropertyDiffUndoRecorder

    执行顺序

    • RecordObject
    • 处理属性
    • Flush
    • 输出差异
    差异示意图

    差异的代码查看

        [MenuItem("Example/Random Rotate")]
        static void RandomRotate()
        {
            var transform = Selection.activeTransform;
            if (transform)
            {
                //Undo.RecordObject(transform,"Rotate " + transform.name);
                //Undo.RegisterCompleteObjectUndo(transform, "Rotate " + transform.name);
                Undo.willFlushUndoRecord += () => Debug.Log("flush");
                Undo.postprocessModifications += (modifications) =>
                {
                    Debug.Log("modifications");
                    return modifications;
                };
                Undo.RecordObject(transform, "Rotate" + transform.name);
                Debug.Log("record");
    
                transform.rotation = Random.rotation;
                Debug.Log("changed");
            }
        }
    
    查看Debug
    Debug

    Redo的实现

    正常执行 Undo Redo

    Undo处理的对象

    Undo定位的是一个可序列化的对象,继承自UnityEngine.Object

    Undo支持的对象

    GameObject
    Component (MonoBehaviour)
    ScriptableObject

    System.Serializable序列化后可以被Undo

    // 序列化
    [System.Serializable]
    public class PlayerInfo
    {
        public string name;
        public int hp;
    }
    
    public class PlayerRedo : MonoBehaviour
    {
        [SerializeField]
        public PlayerInfo info;
    }
    // 调用
    public class ExampleRedo {
        [MenuItem("Example/Change PlayerInfo")]
        static void ChangePlayerInfo()
        {
            var player = Selection.activeGameObject.GetComponent<PlayerRedo>();
    
            if (player)
            {
                Undo.RecordObject(player, "Change PlayerInfo");
                player.info = new PlayerInfo
                {
                    name = "New PlayerName",
                    hp = Random.Range(0, 10)
                };
            }
        }
    }
    

    Undo处理的类型

    • 对象属性
    • 对象本身的操作

    属性撤销[可以实现绝大部分功能]

    [MenuItem("Undo/RecordObject测试")]
        static void RecordObject()
        {
            Transform transform = Selection.activeTransform;
    
            Undo.RecordObject(transform, "position 指定变更为 Vector3(0,0,0)");
            transform.position = new Vector3(0,0,0);
        }
    
    自定义的名字最好是英文,对中文字符支持不好

    一些自带的Undo

        [MenuItem("Undo/AddComponent")]
        static void AddComponent()
        {
            GameObject go = Selection.activeGameObject;
            Rigidbody rigidbody = Undo.AddComponent<Rigidbody>(go);
        }
    
        [MenuItem("Undo/RegisterCreatedObjectUndo")]
        static void RegisterCreatedObjectUndo()
        {
            GameObject go = new GameObject();
            Undo.RegisterCreatedObjectUndo(go, "GameObject 生成");
            // 组的概念
            Undo.IncrementCurrentGroup();
    
            ScriptableRedo scriptableRedo = ScriptableObject.CreateInstance<ScriptableRedo>();
            Undo.RegisterCreatedObjectUndo(scriptableRedo, "ScriptableObject 生成");
    
            //EditorApplication.update += () => Debug.Log(scriptableRedo);
        }
    
        [MenuItem("Undo/DestoryObjectImmediate")]
        static void DestoryObjectImmediate()
        {
            GameObject go = Selection.activeGameObject;
            Undo.DestroyObjectImmediate(go);
        }
    
        [MenuItem("Undo/SetTransformParent")]
        static void SetTransformParent()
        {
            Transform root = GameObject.Find("Main Camera").transform;
            Transform transform = Selection.activeTransform;
            transform.SetParent(root);
            //Undo.SetTransformParent(transform, root, "摄像机子物体");
        }
    

    Revert 表示不想要恢复

    Revert

    Undo.RevertAllInCurrentGroup Revert当前组

        [MenuItem("Undo/RevertAllInCurrentGroup")]
        static void RevertAllInCurrentGroup()
        {
            GameObject ticket = new GameObject("Ticket");
            Undo.RegisterCreatedObjectUndo(ticket,"Ticket");
    
            int number = ticket.GetInstanceID();
    
            int winningNumber = 1234;
    
            if (number != winningNumber)
            {
                Undo.RevertAllInCurrentGroup();
            }
        }
    

    Undo.RevertAllDownToGroup Revert到指定的组索引

    //RevertAllDownToGroup
    public class ExampleRevertUndoWindow : EditorWindow
    {
        [MenuItem("Undo/Window/RevertUndoWindow")]
        static void Open()
        {
            GetWindow<ExampleRevertUndoWindow>();
        }
    
        private GameObject go;
    
        private int group1 = 0;
        private int group2 = 0;
        private int group3 = 0;
    
        void OnEnable()
        {
            go = GameObject.Find("New Game Object");
        }
    
        void OnGUI()
        {
            if (Event.current.type == EventType.MouseDown)
            {
                group1 = Undo.GetCurrentGroup();
    
                Undo.AddComponent<Rigidbody>(go);
    
                Undo.IncrementCurrentGroup();
    
                group2 = Undo.GetCurrentGroup();
    
                Undo.AddComponent<BoxCollider>(go);
    
                Undo.IncrementCurrentGroup();
    
                group3 = Undo.GetCurrentGroup();
    
                Undo.AddComponent<ConstantForce>(go);
            }
    
            if (Event.current.type == EventType.MouseUp)
            {
                Undo.RevertAllDownToGroup(group2);
    
                EditorGUIUtility.ExitGUI();
            }
        }
    }
    

    组的概念

    一般写到一段处理代码里面的操作,被划为一组

    Undo.IncrementCurrentGroup 单独执行每个撤消

        [MenuItem("Undo/RegisterCreatedObjectUndo")]
        static void RegisterCreatedObjectUndo()
        {
            GameObject go = new GameObject();
            Undo.RegisterCreatedObjectUndo(go, "GameObject 生成");
            // 组的概念
            Undo.IncrementCurrentGroup();
    
            ScriptableRedo scriptableRedo = ScriptableObject.CreateInstance<ScriptableRedo>();
            Undo.RegisterCreatedObjectUndo(scriptableRedo, "ScriptableObject 生成");
    
            //EditorApplication.update += () => Debug.Log(scriptableRedo);
        }
    

    CollapseUndoOperations 组合多个Undo

    //CollapseUndo
    public class ExampleCollapseUndo : EditorWindow
    {
        private int groupID = 0;
        [MenuItem("Undo/Window/CollapseUndoWindow")]
        static void Open()
        {
            GetWindow<ExampleCollapseUndo>();
        }
    
        void OnEnbable()
        {
            groupID = Undo.GetCurrentGroup();
        }
    
        void OnDisable()
        {
            Undo.CollapseUndoOperations(groupID);
        }
    
        void OnGUI()
        {
            if (GUILayout.Button("cube"))
            {
                var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
                Undo.RegisterCreatedObjectUndo(cube, "Create cube");
            }
    
            if (GUILayout.Button("plane"))
            {
                var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
                Undo.RegisterCreatedObjectUndo(plane, "Create plane");
            }
    
            if (GUILayout.Button("Cylinder"))
            {
                var cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
                Undo.RegisterCreatedObjectUndo(cylinder, "Create cylinder");
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:【Unity3d编辑器从入门到精通】深入简出聊Undo

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