使用Unity怎么實現(xiàn)一個游戲存檔框架,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
創(chuàng)新互聯(lián)長期為近千家客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為天寧企業(yè)提供專業(yè)的成都網(wǎng)站建設(shè)、成都網(wǎng)站制作,天寧網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
ISavable,表示這個類型可以存檔
public interface ISavable{ uint Id {get; set;} Type DataType {get;} // 存檔數(shù)據(jù)類型 Type DataContainerType {get;} // 存檔數(shù)據(jù)容器類型 void Read(object data); void Write(object data);}
ISavableContainer,用來返回一組ISavable的容器:
public interface ISavableContainer{ IEnumerable
IId, 具有Id的接口:
public interface IId{ uint Id {get; set;}}
SaveEntity, 這是一個MonoBehaviour,將這個組件放到需要存檔的GameObject上就可以實現(xiàn)該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
SaveFile代表一個文件
[Serializable]public class SaveFileData{ public uint CurId; public string DataContainer;} // 代表一個存檔文件public class SaveFile: MonoBehaviour{ // 包含實際數(shù)據(jù)的數(shù)據(jù)類 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
SaveDataContainer:
// 這個類型存儲了實際的數(shù)據(jù),相當(dāng)于是一個數(shù)據(jù)庫[Serializable]public class SaveDataContainer{ // 這個中存儲這實際物體的數(shù)據(jù),需要將這個字典轉(zhuǎn)換成數(shù)組并序列化 private Dictionary
好了,框架就講到這里,接下來實現(xiàn)示例代碼:
Unit:
[Serializable]public class UnitSave:IId{ [SerializeField] private uint _id; public uint PrefabId; public uint InventoryId; public int Hp; public int Level; public uint Id {get{return _id;}set{_id = value;}}} public class Unit:MonoBehaviour, ISavable{ public int Hp; public int Level; public int PrefabId; public Inventory Inventory; public uint Id{get;set;} ISavable.DataType{get{return typeof(UnitSave);}} ISavable.DataContainerType{get{return typeof(ExampleSaveDataContainer);}} ISavable.Read(object data){ UnitSave save = data as UnitSave; Hp = save.Hp; Level = save.Level; } ISavable.Write(object data){ UnitSave save = data as UnitSave; save.Hp = Hp; save.Level = Level; save.InventoryId = Inventory.Id; }}
Inventory:
[Serializable]public class InventorySave:IId{ [SerializeField] private uint _id; public uint UnitId; public uint[] Items; public uint Id{get{return _id;}set{_id = value;}}} public class Inventory:MonoBehaviour, ISavable, ISavableContainer{ public Unit Unit; public List
Item:
[Serializable]public ItemSave: IId{ [SerializeField] private uint _id; public uint PrefabId; public int Count; public uint Id{get{return _id;}set{_id = value;}}} // 道具并不是繼承自MonoBehaviour的,是一個普通的類public class Item:ISavable{ // 道具源數(shù)據(jù)所在Prefab,用于重新創(chuàng)建道具 public uint PrefabId; public int Count; public uint Id {get;set;} public uint Id{get;set;} ISavable.DataType{get{return typeof(ItemSave);}} ISavable.DataContainerType{get{return typeof(ExampleSaveDataContainer));}} ISavable.Read(object data){ ItemSave save = data as ItemSave; Count = save.Count; } ISavable.Write(object data){ ItemSave save = data as ItemSave; save.PrefabId = PrefabId; save.Count = Count; }}
ExampleSaveDataContainer:
[Serializable]public class ExampleSaveDataContainer: SaveDataContainer, ISerializationCallbackReceiver { public UnitSave[] Units; public ItemSave[] Items; public InventorySave[] Inventories; public void OnBeforeSerialize(){ // 將Data字典中的數(shù)據(jù)復(fù)制到數(shù)組中,實現(xiàn)略過 } public void OnAfterDeserialize(){ // 將數(shù)組中的數(shù)據(jù)賦值到Data字典中,實現(xiàn)略過 }}
ExampleGame:
public class ExampleGame:MonoBehaviour{ public void LoadGame(SaveFile file){ // 從文件中讀入數(shù)據(jù)到SaveDataContainer file.LoadFromFile
使用方法:
給單位Prefab中的Unit組件和Inventory組件所在的GameObject上放SaveEntity組件即可。
思考問題:
1.擴展功能,讓SaveFile包含一個SaveDataContainer數(shù)組,這樣子可以實現(xiàn)包含多個數(shù)據(jù)容器(數(shù)據(jù)庫)的情況2.對SaveFile存儲內(nèi)容進行壓縮,減少存儲體積3.SaveFile存儲到文件時進行加密,避免玩家修改存檔4.如何避免存儲時候卡頓
存儲過程:
1.從場景中搜集數(shù)據(jù)到SaveFile中(SaveFile.Save),得到一個SaveFileData的數(shù)據(jù)2.將SaveFileData序列化成一個json字符串3.對字符串進行壓縮4.對壓縮后的數(shù)據(jù)進行加密5.將加密后的數(shù)據(jù)存儲于文件
可以發(fā)現(xiàn),只要完成第1步,得到一個SaveFileData,實際上就已經(jīng)完成了存檔了,接下來實際上就是一個數(shù)據(jù)轉(zhuǎn)換的過程。所以,這也給出了避免游戲卡頓的一種方法:
完成第一步之后,將后面的步驟全部都放到另一個線程里面處理。實際上,第一步的速度是相當(dāng)快的。往往不會超過50ms,可以說,卡頓并不會很明顯。
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。