Unity实现游戏存档框架

作者:hackerzhuli 时间:2023-02-10 13:05:15 

最近重构了一下我的存档框架。我在这里对实现方法进行简单的解析。注意这里主要演示算法,所以,效率上并不是最佳。一个游戏中,可能有成百上千个物体需要存储,而且有几十种类型,接下来就用一个简单的例子来解释。一个很简单的例子,有一个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);
 }
}

SaveDataContainer:


// 这个类型存储了实际的数据,相当于是一个数据库
[Serializable]
public class SaveDataContainer{
 // 这个中存储这实际物体的数据,需要将这个字典转换成数组并序列化
 private Dictionary<uint, IId> _data;

public Dictionary<unit, IId> Data{get{return _data}}

public IId GetData(uint id){
   return _data[id];
 }

public void SetData(IId data){
   _data[data.Id] = data;
 }
}

来源:https://blog.csdn.net/mynameiszhuli/article/details/104026295

标签:Unity,游戏存档
0
投稿

猜你喜欢

  • 用C#缩小照片上传到各种空间的具体方法

    2022-03-28 02:29:18
  • JAVA实现简单系统登陆注册模块

    2021-11-05 05:41:50
  • Android监听键盘状态获取键盘高度的实现方法

    2023-12-02 16:44:17
  • Intellij IDEA 2019 最新乱码问题及解决必杀技(必看篇)

    2023-12-04 18:30:02
  • SpringBoot中Jackson日期格式化技巧分享

    2022-05-21 01:40:24
  • 基于Ok+Rxjava+retrofit实现断点续传下载

    2021-08-27 02:21:49
  • Android 如何定制vibrator的各种震动模式M 具体方法

    2023-08-13 02:09:01
  • Android系统工具类详解

    2023-07-12 22:11:57
  • Mybatis无法获取带有下划线前缀的字段的值问题

    2023-07-20 10:06:33
  • 利用Android画圆弧canvas.drawArc()实例详解

    2022-05-21 08:45:54
  • Unity动画混合树实例详解

    2022-06-17 14:41:27
  • Java 获取网站图片的示例代码

    2022-03-11 14:52:44
  • struts2 validation.xml 验证规则代码解析

    2021-09-14 22:01:27
  • C#实现实体类和XML相互转换

    2023-06-16 04:37:32
  • C#值类型、引用类型中的Equals和==的区别浅析

    2022-09-05 23:04:24
  • 25个最好的免费Eclipse插件

    2021-09-21 10:56:24
  • android,不显示标题的方法小例子

    2023-07-10 17:14:36
  • 详解c# 类的构造方法

    2023-02-10 17:17:19
  • Spring EL表示式的运用@Value说明

    2023-03-05 02:33:19
  • C# 指针内存控制Marshal内存数据存储原理分析

    2021-09-22 04:05:00
  • asp之家 软件编程 m.aspxhome.com