Unity 实现备忘录模式
备忘录模式的关键是将对象的状态封装到备忘录中,从而实现状态的存储和回滚,而不破坏对象的封装性。通过备忘录模式,Unity中的状态管理变得更加模块化和灵活,尤其在游戏开发中的存档/加载功能中非常实用。如果备忘录需要存储大量数据(如复杂的游戏状态),需要注意内存管理,定期清理过期的备忘录。可以将备忘录的数据序列化为JSON或XML文件,保存到磁盘,从而实现游戏的存档功能。如果数据比较敏感,可以对备忘录
备忘录模式(Memento Pattern)是一种行为型设计模式,允许保存对象的某个状态,以便在未来可以恢复到这个状态。备忘录模式的关键是将对象的状态封装到备忘录中,从而实现状态的存储和回滚,而不破坏对象的封装性。
在Unity中,备忘录模式非常适用于以下场景:
- 游戏存档和加载:保存和恢复玩家的游戏进度。
- 撤销和重做功能:保存玩家的操作状态以支持撤销。
- 临时状态保存:如玩家的角色状态、物品状态等。
1. 备忘录模式的基本概念
核心结构
备忘录模式包含以下几个部分:
- 发起人(Originator):对象的状态需要被保存或恢复。
- 备忘录(Memento):存储发起人的内部状态。
- 管理者(Caretaker):负责保存和恢复备忘录。
优点
- 封装性好:备忘录存储的是发起人的内部状态,但对外界不可见。
- 简化撤销和恢复功能:通过备忘录可以轻松实现状态的回滚。
- 扩展性强:可以保存和恢复复杂的数据结构。
缺点
- 内存开销大:如果状态数据较多,存储多个备忘录可能会占用大量内存。
- 实现复杂度高:需要设计备忘录的存储和管理逻辑。
- 数据一致性问题:需要确保备忘录和发起人状态的一致性。
2. Unity 实现备忘录模式
以下通过一个示例,展示如何在Unity中用备忘录模式实现玩家位置和状态的保存与恢复。
3. 实现步骤
(1) 定义备忘录类
备忘录类负责存储发起人的状态。可以是玩家的位置、生命值、分数等。
// PlayerMemento.cs
using UnityEngine;
public class PlayerMemento
{
public Vector3 Position { get; private set; }
public int Health { get; private set; }
public PlayerMemento(Vector3 position, int health)
{
Position = position;
Health = health;
}
}
(2) 定义发起人类
发起人类保存当前状态,并创建备忘录或从备忘录中恢复状态。
// Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
public Vector3 Position { get; set; }
public int Health { get; set; }
// 创建备忘录
public PlayerMemento SaveState()
{
Debug.Log("Saving state...");
return new PlayerMemento(Position, Health);
}
// 从备忘录恢复状态
public void RestoreState(PlayerMemento memento)
{
Position = memento.Position;
Health = memento.Health;
Debug.Log($"Restoring state... Position: {Position}, Health: {Health}");
}
private void Update()
{
// 模拟玩家移动
if (Input.GetKey(KeyCode.W))
{
Position += Vector3.forward * Time.deltaTime;
}
// 模拟玩家受伤
if (Input.GetKeyDown(KeyCode.Space))
{
Health -= 10;
Debug.Log($"Player took damage. Current health: {Health}");
}
}
}
(3) 定义管理者类
管理者类负责保存和管理多个备忘录(如果需要支持多个存档)。
// Caretaker.cs
using System.Collections.Generic;
public class Caretaker
{
private Stack<PlayerMemento> _mementos = new Stack<PlayerMemento>();
// 保存备忘录
public void SaveMemento(PlayerMemento memento)
{
_mementos.Push(memento);
Debug.Log("State saved.");
}
// 恢复备忘录
public PlayerMemento RestoreMemento()
{
if (_mementos.Count > 0)
{
Debug.Log("State restored.");
return _mementos.Pop();
}
Debug.LogWarning("No state to restore!");
return null;
}
}
(4) 测试备忘录模式
创建一个测试脚本,模拟保存和恢复玩家状态。
// GameManager.cs
using UnityEngine;
public class GameManager : MonoBehaviour
{
private Player _player;
private Caretaker _caretaker;
private void Start()
{
_player = new GameObject("Player").AddComponent<Player>();
_caretaker = new Caretaker();
// 初始化玩家状态
_player.Position = Vector3.zero;
_player.Health = 100;
Debug.Log($"Initial state: Position={_player.Position}, Health={_player.Health}");
}
private void Update()
{
// 保存状态
if (Input.GetKeyDown(KeyCode.S))
{
_caretaker.SaveMemento(_player.SaveState());
}
// 恢复状态
if (Input.GetKeyDown(KeyCode.R))
{
var memento = _caretaker.RestoreMemento();
if (memento != null)
{
_player.RestoreState(memento);
}
}
// 显示当前状态
if (Input.GetKeyDown(KeyCode.P))
{
Debug.Log($"Current state: Position={_player.Position}, Health={_player.Health}");
}
}
}
4. 运行结果
运行游戏后,按下以下键可以测试功能:
W
:移动玩家位置。Space
:减少玩家生命值。S
:保存当前状态。R
:恢复上一次保存的状态。P
:查看当前状态。
控制台输出示例:
Initial state: Position=(0.0, 0.0, 0.0), Health=100
Player took damage. Current health: 90
Saving state...
Player took damage. Current health: 80
State restored.
Restoring state... Position=(0.0, 0.0, 0.0), Health=90
5. 扩展与优化
(1) 添加多个存档
目前的实现只保存了一个存档。如果需要支持多个存档,可以使用一个List<PlayerMemento>
或Dictionary<string, PlayerMemento>
来存储多个备忘录。
private Dictionary<string, PlayerMemento> _mementos = new Dictionary<string, PlayerMemento>();
public void SaveMemento(string key, PlayerMemento memento)
{
_mementos[key] = memento;
Debug.Log($"State saved with key: {key}");
}
public PlayerMemento RestoreMemento(string key)
{
if (_mementos.ContainsKey(key))
{
Debug.Log($"State restored with key: {key}");
return _mementos[key];
}
Debug.LogWarning($"No state found with key: {key}");
return null;
}
(2) 结合序列化存储到文件
可以将备忘录的数据序列化为JSON或XML文件,保存到磁盘,从而实现游戏的存档功能。
using System.IO;
using Newtonsoft.Json;
public void SaveToFile(PlayerMemento memento, string filePath)
{
var json = JsonConvert.SerializeObject(memento);
File.WriteAllText(filePath, json);
Debug.Log("State saved to file.");
}
public PlayerMemento LoadFromFile(string filePath)
{
if (File.Exists(filePath))
{
var json = File.ReadAllText(filePath);
return JsonConvert.DeserializeObject<PlayerMemento>(json);
}
Debug.LogWarning("Save file not found.");
return null;
}
(3) Undo/Redo 功能
通过维护两个栈(一个用于撤销,一个用于重做),可以轻松实现撤销/重做功能。
6. 优化与注意事项
(1) 内存管理
如果备忘录需要存储大量数据(如复杂的游戏状态),需要注意内存管理,定期清理过期的备忘录。
(2) 数据一致性
确保备忘录存储的数据完全反映发起人的状态,避免数据不一致的问题。
(3) 备忘录的安全性
如果数据比较敏感,可以对备忘录的访问进行限制,例如设置为只读或通过加密存储。
7. 总结
备忘录模式的优缺点
优点 | 缺点 |
---|---|
封装了对象的状态,便于保存和恢复。 | 如果状态较多,可能会占用大量内存。 |
简化了撤销和恢复功能的实现。 | 实现复杂度较高,尤其是管理多个备忘录时。 |
不破坏封装性,对外界隐藏发起人的内部状态。 | 如果涉及文件存储,序列化和反序列化可能会增加额外的复杂性。 |
适用场景
- 游戏存档和加载:保存和恢复玩家的游戏进度。
- Undo/Redo 功能:例如地图编辑器、道具操作等。
- 临时状态保存:如关卡切换时保存玩家状态以便恢复。
通过备忘录模式,Unity中的状态管理变得更加模块化和灵活,尤其在游戏开发中的存档/加载功能中非常实用。
更多推荐
所有评论(0)