当我们需要读取战机的属性时,有时会发生冲突,我们不知道需要从配置中读取属性还是从存档中读取属性。
这时我们使用配置管理器,在游戏一开始时初始化所有配置,把配置信息都写入存档中。
ConfigMgr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| using LitJson;
public class ConfigMgr : NormalSingleton<ConfigMgr> { public void Init() { var config = ReaderMgr.Instance.GetReader(Path.INIT_PLANE_CONFIG); config["planes"].Get<JsonData>(data => { foreach (JsonData item in data) { foreach (string key in item.Keys) { if (key == "planeId") continue; string saveKey = KeysUtil.GetPropertyKeys(int.Parse(item["planeId"].ToJson()), key); if (!DataMgr.Instance.Contains(saveKey)) { DataMgr.Instance.Set(saveKey,item[key]); } } } }); } }
|
在GameRoot
一开始时调用
1 2 3 4 5 6 7 8
| private void Start() { DataMgr.Instance.ClearAll(); ConfigMgr.Instance.Init(); InitCustomAttributes initCustomAttributes = new InitCustomAttributes(); }
|
修改存档相关
IDataMemory
添加Contains
方法,用于判断存档中是否有对应的值
1 2 3 4 5
| public interface IDataMemory { bool Contains(string key); }
|
DataMgr
1 2 3 4
| public bool Contains(string key) { return m_data.Contains(key); }
|
PlayerPrefsMemory
1 2 3 4
| public bool Contains(string key) { return PlayerPrefs.HasKey(key); }
|
KeysUtil
因为每一个飞机的属性值名称相同,但是飞机的id不同,我们需要一个工具来提供每个飞机的属性的精确键值。这些精确的键值能够帮助我们精确地使用DataMgr
进行存档读档。
1 2 3 4 5 6 7
| public class KeysUtil { public static string GetPropertyKeys(int id,string name) { return id + name; } }
|
JsonReader相关
我们需要遍历一个JsonData
对象目前所有的Key值,方便ConfigMgr
来设定存档所用的键值。LitJson.JsonData
实现了类似IList
、IDictionary
等接口,我们可以直接将JsonData对象放在foreach语法当中遍历,从而获取所有key值。JsonData也提供了Keys属性,为ICollection<string>
类型。
IReader
1 2 3 4 5 6 7
| using System.Collections.Generic;
public interface IReader { ICollection<string> Keys(); }
|
JsonReader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private T GetValue<T>(JsonData data) { TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); try { if (converter.CanConvertTo(typeof(T))) { return (T)converter.ConvertTo(data.ToString(), typeof(T)); } else { return (T)(object)data; } } catch (Exception ex) { Debug.LogError("当前类型转换不支持:" + typeof(T).Name + " data: " + data); return default; } } public ICollection<string> Keys() { if(_tempData == null) return new string[0]; return _tempData.Keys; }
|
如果我们想要调用到Keys()
,必须保证当前的_tempData
缓存的JsonData是我们想要的数据。
但是我们可以直接获取JsonData,不使用Keys()
方法,我们修改了GetValue<T>
方法,让它可以返回JsonData,之所以修改是因为TypeConverter
不支持转换为JsonData,我们需要(T)(object)data
这种操作。
DataUtil
这个工具使用静态拓展来拓展DataMgr.Set
方法,更加方便地进行类型转换。虽然我们调用PlayerPrefsMemory.Set
时会自动判断数据类型,但是有些存储在Json中的数据都是string类型,我们使用这个拓展方法来把json中的数据先更准确的进行转化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| using LitJson; using UnityEngine;
public static class DataUtil { public static void Set(this DataMgr dataMgr, string key, JsonData json) { IJsonWrapper jsonWrapper = json; switch (json.GetJsonType()) { case JsonType.None: Debug.LogError("当前JsonData数据为空"); break; case JsonType.String: DataMgr.Instance.Set(key, jsonWrapper.GetString()); break; case JsonType.Int: DataMgr.Instance.Set(key, jsonWrapper.GetInt()); break; case JsonType.Long: DataMgr.Instance.Set(key, (int)jsonWrapper.GetLong()); break; case JsonType.Double: DataMgr.Instance.Set(key, (float)jsonWrapper.GetDouble()); break; } } }
|
LitJson.JsonData.GetJsonType
方法是LitJson内部提供的获取类型信息的方法。使用JsonType
枚举来表示每个json所代表的信息。
JsonData类实现了IJsonWrapper
接口,这个接口就是用来获取Json对应的类型的值的,但是在JsonData类里面这个接口被显式调用了,这意味着我们不能使用类似jsonData.GetInt()
来获取值,只能在方法内先通过声明IJsonWrapper
变量来转换jsonData从而调用接口提供的方法。