UnityEditorUnity编辑器开发分享Unity基础入门分享

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

2017-09-28  本文已影响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

执行顺序

差异示意图

差异的代码查看

    [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");
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读