属性绑定式的响应——全自动序列化和反序列化
昨天在做游戏配置项的本地化存储
想着把这个东西做的智能一点 完全不需要操心序列化的时机和反序列化的时机
所以就考虑了属性绑定式的响应
去监听属性的修改 只要有属性被修改就能够自动被序列化到本地
求助了一下万能的gpt 在它的帮助下最终实现是这样的
using System; using UnityEngine; using System.ComponentModel; [Serializable] public class GameSetting : INotifyPropertyChanged { [SerializeField] private bool birthPlace = true; public bool BirthPlace { get => birthPlace; set { if (birthPlace != value) { birthPlace = value; OnPropertyChanged(nameof(BirthPlace)); } } } [SerializeField] private bool test_0 = true; public bool Test_0 { get => test_0; set { if (test_0 != value) { test_0 = value; OnPropertyChanged(nameof(test_0)); } } } //新增属性只要像Test_0这样就可以了 public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class GameSettingManager { private static readonly string KEY = "GameSetting"; public static GameSettingManager Instance { get; } = new GameSettingManager(); private GameSetting config; public GameSetting Config { get { if (config == null) { //单例内的config为空的时候 要去反序列化一遍 config = LoadGameSetting(); //注册一下监听的方法 config.PropertyChanged += OnConfigPropertyChanged; } return config; } set { if (value == null) { Debug.LogError("不能空 如果要直接Set一定要传值"); } if (config != null) { //不为空 先取消旧的监听事件 config.PropertyChanged -= OnConfigPropertyChanged; } config = value; //重新修改后 要再添加新的监听事件 config.PropertyChanged += OnConfigPropertyChanged; SaveGameSetting(config); } } private GameSettingManager() { if (Instance != null) { Debug.LogError("出现了多个游戏设置单例,要检查一下为什么"); } } /// <summary> /// 保存游戏设置 /// </summary> /// <param name="config"></param> private void SaveGameSetting(GameSetting config) { string json = JsonUtility.ToJson(config); PlayerPrefs.SetString(KEY, json); Debug.Log("触发游戏设置序列化操作" + json); } /// <summary> /// 加载游戏设置 /// </summary> /// <returns></returns> private GameSetting LoadGameSetting() { if (PlayerPrefs.HasKey(KEY)) { string json = PlayerPrefs.GetString(KEY); Debug.Log("触发游戏设置反序列化操作" + json); var config = JsonUtility.FromJson<GameSetting>(json); //每次新的对象都要注册一下 config.PropertyChanged += OnConfigPropertyChanged; return config; } else { //没有的话就创建一个新的 参数都给默认值 var config = new GameSetting { BirthPlace = true }; //同上 新对象都要注册一下 config.PropertyChanged += OnConfigPropertyChanged; SaveGameSetting(config); return config; } } private void OnConfigPropertyChanged(object sender, PropertyChangedEventArgs e) { if (sender == Config) { //在这里还可以通过判断e的属性名来做不同的操作 switch (e.PropertyName) { case nameof(GameSetting.BirthPlace): // 处理 BirthPlace 属性改变的逻辑 break; case nameof(GameSetting.Test_0): // 处理 Test_0 属性改变的逻辑 break; // 添加其他属性的处理逻辑 default: break; } SaveGameSetting(Config); } } }
这个方法缺点也很明显
全自动看起来很高端 但完全不可控
假如说有一个玩家很手贱 一直在修改这些配置
那序列化就会在短时间内一直发生
可能会引起比较明显的卡顿的现象
所以最终老大哥没有采用这个方案
还是选了最简单的 把序列化暴露出来交给外面控制
当然你还可以用比较古典的SetDirty的方法
做一下标记 退出页面的时候只要带有脏标记就弹窗提示一下保存