最近重构了一下我的存档框架。我在这里对实现方法进行简单的解析。注意这里主要演示算法,所以,效率上并不是最佳。一个游戏中,可能有成百上千个物体需要存储,而且有几十种类型,接下来就用一个简单的例子来解释。一个很简单的例子,有一个Unit(单位)类型,有一个Inventory(背包)类型,有一个Item(道具)类型。
接下来先介绍框架中最重要的接口,ISavable,表示这个类型可以存档
public interface ISavable{ uint Id {get; set;} Type DataType {get;} // 存档数据类型 Type DataContainerType {get;} // 存档数据容器类型 void Read(object data); void Write(object data); }
ISavableContainer,用来返回一组ISavable的容器:
public interface ISavableContainer{ IEnumerable<ISavable> Savables; }
IId, 具有Id的接口:
public interface IId { uint Id {get; set;} }
SaveEntity, 这是一个MonoBehaviour,将这个组件放到需要存档的GameObject上就可以实现该GameObject的存档了,这是最核心的类之一:
public class SaveEntity : MonoBehaviour{ public void Save(SaveDataContainer container){ foreach(ISavable savable in GetSavables()){ if(savable.DataContainerType = container.GetType()){ IId newData = Activator.CreateInstance(savable.DataType) as IId; newData.Id = savable.Id; savable.Write(newData); container.SetData(newData); } } } public void Load(SaveDataContainer container){ foreach(ISavable savable in GetSavables()){ if(savable.DataContainerType = container.GetType()){ IId data = container.GetData(savable.Id); savable.Read(data); } } } public IEnumerable<ISavable> GetSavables(){ foreach(ISavable savable in GetComponents<ISavable>()){ yield return savable; } foreach(ISavable savableContainer in GetComponents<ISavableContainer>()){ foreach(ISavable savable in savableContainer.Savables){ yield return savable; } } } }
SaveFile代表一个文件
[Serializable] public class SaveFileData{ public uint CurId; public string DataContainer; } // 代表一个存档文件 public class SaveFile: MonoBehaviour{ // 包含实际数据的数据类 private SaveDataContainer _saveDataContainer; private uint _curId; public string Path{get;set;} public SaveDataContainer SaveDataContainer{get{return _saveDataContainer;}} private uint NextId{get{return ++_curId;}} // 得到场景里所有的SaveEntity private IEnumerable<SaveEntity> GetEntities(){ // 实现略过 } // 将场景物体中的数据存入到_saveDataContainer中 public void Save<T>() where T:SaveDataContainer, new() { // 一轮Id赋值,保证Id为0的所有ISavable都赋值一个新Id foreach(SaveEntity entity in Entities){ foreach (Savable savable in entity.GetSavables()){ if(savable.DataContainerType == typeof(T)){ if(savable.Id == 0){ savable.Id = NextId; } } } } T dataContainer = new T(); foreach(SaveEntity entity in Entities){ entity.Save(this, dataContainer); } _saveDataContainer = dataContainer; } // 将_saveDataContainer中的数据载入到场景物体中 public void Load(){ foreach(SaveEntity entity in Entities){ entity.Load(this, _saveDataContainer); } } public void LoadFromFile<T>() where T:SaveDataContainer { string json = File.ReadAllText(Path); SaveFileData data = JsonUtility.FromJson<SaveFileData>(json); _saveDataContainer = JsonUtility.FromJson<T>(data.DataContainer); _curId = data.CurId; } public void SaveToFile(){ SaveFileData data = new SaveFileData(); data.CurId = _curId; data.DataContainer = JsonUtility.ToJson(_saveDataContainer); string json = JsonUtility.ToJson(data); File.WriteAllText(Path, json); } }