Unity 备忘录模式(实例详解)


Unity中的备忘录模式(Memento Pattern)主要用于保存和恢复对象的内部状态,而不会暴露对象的实现细节。下面通过5个代码片段来展示在Unity中如何使用备忘录模式:

示例1 - 简单的角色血量管理

using UnityEngine;
using System.Collections;

public class Character : MonoBehaviour
{
    // 内部状态
    private int currentHealth;

    // 备忘录类
    public class HealthMemento
    {
        public int Health { get; private set; }

        public HealthMemento(int health)
        {
            Health = health;
        }
    }

    // 创建备忘录
    public HealthMemento CreateMemento()
    {
        return new HealthMemento(currentHealth);
    }

    // 恢复备忘录
    public void RestoreMemento(HealthMemento memento)
    {
        currentHealth = memento.Health;
    }

    // 更新血量
    public void ChangeHealth(int amount)
    {
        currentHealth += amount;
        Debug.Log("当前血量: " + currentHealth);
    }

    private void Start()
    {
        currentHealth = 100;
        SaveCurrentState();
        ChangeHealth(-20); // 受伤
        RestorePreviousState();
    }

    // 保存和恢复方法
    private HealthMemento savedMemento;
    private void SaveCurrentState()
    {
        savedMemento = CreateMemento();
    }

    private void RestorePreviousState()
    {
        RestoreMemento(savedMemento);
    }
}

示例2 - 游戏角色装备系统

using UnityEngine;
using System.Collections.Generic;

public class Player : MonoBehaviour
{
    private Dictionary<string, Item> equipment;

    // 备忘录类
    public class EquipmentMemento
    {
        public Dictionary<string, Item> Snapshot { get; private set; }

        public EquipmentMemento(Dictionary<string, Item> snapshot)
        {
            Snapshot = new Dictionary<string, Item>(snapshot);
        }
    }

    // 创建备忘录
    public EquipmentMemento CreateEquipmentMemento()
    {
        return new EquipmentMemento(new Dictionary<string, Item>(equipment));
    }

    // 恢复备忘录
    public void RestoreEquipmentMemento(EquipmentMemento memento)
    {
        equipment = new Dictionary<string, Item>(memento.Snapshot);
    }

    // 装备更换等操作...
}

// 假设Item是游戏角色装备的一个基类或接口
public class Item { ... }

示例3 - 场景编辑器中的撤销/重做功能

using UnityEngine;
using UnityEditor;

public class SceneEditor : EditorWindow
{
    private class SceneStateMemento
    {
        public SceneView.State stateData;
        // 其他需要存储的状态属性...

        public SceneStateMemento(SceneView sceneView)
        {
            stateData = sceneView.state;
            // 保存其他状态...
        }

        public void ApplyToSceneView(SceneView sceneView)
        {
            sceneView.state = stateData;
            // 应用其他状态...
        }
    }

    Stack<SceneStateMemento> undoStack;
    Stack<SceneStateMemento> redoStack;

    void OnGUI()
    {
        if (GUILayout.Button("Undo"))
        {
            if (undoStack.Count > 0)
            {
                var memento = undoStack.Pop();
                memento.ApplyToSceneView(SceneView.lastActiveSceneView);
                redoStack.Push(memento);
            }
        }

        if (GUILayout.Button("Redo"))
        {
            if (redoStack.Count > 0)
            {
                var memento = redoStack.Pop();
                memento.ApplyToSceneView(SceneView.lastActiveSceneView);
                undoStack.Push(memento);
            }
        }

        // 在执行任何改变场景状态的操作后创建新的备忘录并压入栈
        if (/* 检测到场景状态改变 */)
        {
            var currentState = new SceneStateMemento(SceneView.lastActiveSceneView);
            undoStack.Push(currentState);
            redoStack.Clear();
        }
    }
}

// 这里简化了Unity Editor的实际操作逻辑,真实情况会更复杂。

示例4 - UI布局保存与恢复

using UnityEngine.UIElements;
using UnityEngine;
using System.Collections.Generic;

public class UILayoutSaver
{
    public class LayoutMemento
    {
        public Dictionary<VisualElement, Rect> ElementRects { get; private set; }

        public LayoutMemento(Dictionary<VisualElement, Rect> rects)
        {
            ElementRects = rects;
        }

        public void ApplyLayout()
        {
            foreach (var kvp in ElementRects)
            {
                kvp.Key.style.position = new StylePosition() { left = kvp.Value.x, top = kvp.Value.y };
                kvp.Key.style.width = kvp.Value.width;
                kvp.Key.style.height = kvp.Value.height;
            }
        }
    }

    public LayoutMemento CaptureUILayout(VisualElement root)
    {
        var rectDict = new Dictionary<VisualElement, Rect>();
        CollectElementRects(root, rectDict);
        return new LayoutMemento(rectDict);
    }

    private static void CollectElementRects(VisualElement element, Dictionary<VisualElement, Rect> rects)
    {
        rects[element] = element.layout;
        foreach (var child in element.Children())
        {
            CollectElementRects(child, rects);
        }
    }

    public void RestoreUILayout(LayoutMemento memento, VisualElement root)
    {
        memento.ApplyLayout();
    }
}

示例5 - 动画控制器的状态记录

using UnityEngine;
using UnityEngine.Animations;

public class AnimationController
{
    private Animator animator;
    private class AnimationStateMemento
    {
        public Dictionary<int, float> FloatParameters;
        public Dictionary<int, int> IntegerParameters;
        public Dictionary<int, bool> BoolParameters;

        public AnimationStateMemento(Animator animator)
        {
            FloatParameters = new Dictionary<int, float>();
            IntegerParameters = new Dictionary<int, int>();
            BoolParameters = new Dictionary<int, bool>();

            foreach (var param in animator.parameters)
            {
                switch (param.type)
                {
                    case AnimatorControllerParameterType.Float:
                        FloatParameters[param.nameHash] = animator.GetFloat(param.nameHash);
                        break;
                    case AnimatorControllerParameterType.Int:
                        IntegerParameters[param.nameHash] = animator.GetInteger(param.nameHash);
                        break;
                    case AnimatorControllerParameterType.Bool:
                        BoolParameters[param.nameHash] = animator.GetBool(param.nameHash);
                        break;
                }
            }
        }

        public void ApplyToAnimator(Animator targetAnimator)
        {
            foreach (var pair in FloatParameters)
            {
                targetAnimator.SetFloat(pair.Key, pair.Value);
            }
            foreach (var pair in IntegerParameters)
            {
                targetAnimator.SetInteger(pair.Key, pair.Value);
            }
            foreach (var pair in BoolParameters)
            {
                targetAnimator.SetBool(pair.Key, pair.Value);
            }
        }
    }

    public AnimationStateMemento CreateAnimationStateSnapshot()
    {
        return new AnimationStateMemento(animator);
    }

    public void RestoreAnimationState(AnimationStateMemento memento)
    {
        memento.ApplyToAnimator(animator);
    }

    // 初始化等其他方法...
}

以上示例覆盖了游戏实体、UI布局、动画控制器等多种不同场景下的备忘录模式应用。在实际项目中,根据需求调整备忘录类的具体内容以适应不同对象的状态存储和恢复。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极致人生-010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值