掌握Unity中的保存和加載功能5
Feb 19, 2025 am 09:21 AM
> 如果您需要一個項目才能練習,請以下是我們在上一個教程中完成的項目的版本。它已經使用了一對源自產生的物品的遊戲內相互作用的對象進行升級 - 一把藥水和一把劍。它們可以產生並
拾取>(
下載項目啟動文件
>項目github頁面
項目zip下載
鑰匙要點
>利用委託事件系統來通知對象何時保存其狀態,增強保存/加載系統的模塊化和靈活性。
>使用可序列化類來保存對象屬性(例如位置),可以輕鬆地擴展或修改針對不同類型的對象。 >
確保正確訂閱和取消訂閱以將事件保存在對像腳本中以避免錯誤並有效地管理遊戲狀態。
- 開發一個可靠的系統,用於使用二進制格式來保存和加載,以處理複雜的數據結構並確保數據完整性。
- 測試並擴展系統以包括新的對像類型和功能,證明了系統的適應性和針對不同遊戲開發需求的可伸縮性。
- 實施理論
- >我們需要在實現該對象之前分解保存和加載對象的系統。首先,我們需要某種將產生和絕望對象的對象
- 級別的主體。它需要在級別中保存對象(如果我們正在加載級別而不是重新啟動),Despawn拾取對象,通知對象需要保存自己並管理對象列表。聽起來很多,所以讓我們將其放入流程圖中:
-
>基本上,整個邏輯都將對象列表保存到硬盤驅動器中 - 下次加載級別時,將在我們開始播放時產生的所有對象。聽起來很容易,但是魔鬼在細節中:我們如何知道要保存哪些對象,以及我們如何將它們產生回去?
>>委託和事件
>在上一篇文章中,我提到我們將使用委託事件系統通知對象需要保存自己的對象。讓我們首先解釋什麼是代表和事件。
>>您可以閱讀官方代表文檔和官方事件文檔。但請放心:即使我也不了解官方文檔中的很多技術,所以我會用簡單的英語說:
委託> 這個委託描述了一個函數,該函數什麼都沒有返回(void),並接受.NET/MONO框架的兩個標準參數:代表事件發送者的通用對象,以及最終可以使用的參數,您可以使用這些數據傳遞各種數據。您真的不必擔心這一點,我們可以將(Null,Null)作為爭論,但必須在那裡。public delegate void SaveDelegate(object sender, EventArgs args);
登入後複製登入後複製登入後複製登入後複製登入後複製>
>事件。它僅接受與委託(藍圖)匹配的函數,並且您可以在運行時刪除並刪除函數。 然後,您可以隨時觸發事件,這意味著運行當前框中的所有功能 - 立即運行。考慮以下事件聲明: >訂閱並取消訂閱
訂閱事件基本上意味著“將功能放在框中”。語法很簡單。讓我們假設我們的事件在我們著名的全球視頻類別中聲明,並且我們有一些名為public event SaveDelegate SaveEvent;
登入後複製登入後複製登入後複製登入後複製> potiondroppobable
的藥水對像類,需要訂閱事件:> >
>當我們擁有它時,我們只是在腳本開始或清醒時將該功能放在框中,然後在被銷毀時將其刪除。 (取消訂閱非常重要:如果您嘗試調用被破壞對象的函數,則在運行時會得到null引用異常)。我們通過訪問已聲明的事件對象,然後使用添加操作員然後使用功能名稱來做到這一點。
>注意:我們沒有使用括號或參數調用函數;我們只是使用該函數的名稱,別無其他。
>因此,讓我們解釋一下這一切最終在遊戲的某個示例流中的作用。
>邏輯流> >
這四個對像在保存事件中註冊其功能:> >然後,假設玩家決定保存遊戲 - 也許他們確實需要回答現在響了三遍的手機(嘿,您做了一個很棒的遊戲):
基本上,發生的事情是框中的功能一個一個一個一個一個一個一個觸發的功能,並且在所有功能完成之前,遊戲才能運行到任何地方。每個“保存自身”的對象基本上都在列表中寫下自己 - 在下一個遊戲負載上,將由級別的主對象進行檢查,列表中的所有對像都將進行實例化(產生)。就是這樣:如果您到目前為止遵循了這篇文章,那麼您基本上就可以立即開始實施它。但是,我們將在這裡進行一些具體的代碼示例,一如既往,如果您想看看整個事物應該如何看,就會有一個完成的項目在文章結束時等待您。
>
f5/f9
來保存/加載,則產生的對象將消失。
盒子產卵器和產卵的對象本身使用了一個簡單的可交互接口機械師,該機制使我們能夠識別到這些對象,在屏幕上寫入文本,然後使用[e]鍵與它們進行交互。
沒有更多的存在。我們在這裡的任務是:
- 列出藥水 的列表
- 列出劍對象的列表
- 實施全局保存事件
- >使用保存功能訂閱事件
- 實現級別主對象 如果我們加載了遊戲,則
- 使級別主產生所有保存的對象。 >
>
>對像類列表>以類似的方式,我們需要一些代表我們對象的可序列化類。要編寫它們,我們需要知道我們需要保存的屬性 - 對於我們的玩家,我們有很多東西要保存。幸運的是,對於對象,您很少需要比他們的世界地位更多。在我們的示例中,我們只需要保存對象的位置,而無需保存。
為了很好地構建我們的代碼,我們將從一個簡單的類開始,從我們的序列化末尾開始:
>>public delegate void SaveDelegate(object sender, EventArgs args);
登入後複製登入後複製登入後複製登入後複製登入後複製到目前為止,您可能已經註意到我使用了很多詞> droppable
。這是因為我們需要區分可輟學的(產生)對象和可放置的對象,這些對象遵循不同的保存和產卵規則。我們稍後再解決。>
現在,與玩家的數據不同,我們知道在任何給定時間實際上只有一個玩家,我們可以擁有多個諸如藥水之類的對象。我們需要列出一個動態列表,並表示此列表所屬的場景:我們不能在Level1中spawn Level2的對象。這很容易做到,再次在序列化中。在我們的最後一堂課下面寫這篇文章:
public delegate void SaveDelegate(object sender, EventArgs args);
登入後複製登入後複製登入後複製登入後複製登入後複製列出這些列表實例的最佳場所將是我們的全球控制類別:
public event SaveDelegate SaveEvent;
登入後複製登入後複製登入後複製登入後複製>現在我們的列表非常好:稍後我們將在需要產卵項目時從LevelMaster對象訪問它們,並從GlobalControl內部的硬盤驅動器中保存/加載,就像我們已經使用Player Data一樣。
>委託和事件
啊,終於。讓我們實施著名的活動。
在GlobalControl中>
如您所見,我們正在使活動成為靜態參考,因此以後更邏輯且更易於工作。//In PotionDroppable's Start or Awake function: GlobalObject.Instance.SaveEvent += SaveFunction; //In PotionDroppable's OnDestroy() function: GlobalObject.Instance.SaveEvent -= SaveFunction; //[...] public void SaveFunction (object sender, EventArgs args) { //Here is code that saves this instance of an object. }
登入後複製登入後複製>
>有關事件實施的最後一個說明:只有包含事件聲明的類才能解僱事件。任何人都可以通過訪問globalcontrol.saveevent = ...來訂閱它,但是只有GlobalControl類才能使用SaveEvent(null,null)觸發它。嘗試使用globalcontrol.saveevent(null,null);從其他地方導致編譯器錯誤!>
就是事件實施!讓我們訂閱一些東西!>
>事件訂閱開始聆聽
我們需要一個在事件觸發時運行的函數 - 對於每個對象。讓我們在在觸發事件時進行反應。
>pickups
在PotionDroppable中,添加以下內容: 我們正確地進行了訂閱並取消訂閱活動。現在,問題仍然存在,>文件夾中轉到PotionDroppoppable腳本。注意:Sword還沒有設置其腳本;我們將稍後完成!
>如何將此對象保存在列表中? > 我們首先需要確保我們有針對當前場景初始化的對象列表。 在GlobalControl.cs中: 此功能需要每個級別觸發一次。問題是,我們的全球控制範圍及其開始和清醒功能僅發射一次。我們將通過簡單地從我們的級別主對象調用此函數來解決這個問題,我們將在稍後創建。 我們將需要一個小的輔助功能來返回當前的活動場景列表。在GlobalControl.cs中:[Serializable] public class SavedDroppablePotion { public float PositionX, PositionY, PositionZ; } [Serializable] public class SavedDroppableSword { public float PositionX, PositionY, PositionZ; }
登入後複製登入後複製現在,我們確定我們始終有一個列表可以保存我們的物品。讓我們回到我們的藥水腳本:[Serializable] public class SavedDroppableList { public int SceneID; public List<SavedDroppablePotion> SavedPotions; public List<SavedDroppableSword> SavedSword; public SavedDroppableList(int newSceneID) { this.SceneID = newSceneID; this.SavedPotions = new List<SavedDroppablePotion>(); this.SavedSword = new List<SavedDroppableSword>(); } }
登入後複製public List<SavedDroppableList> SavedLists = new List<SavedDroppableList>();
登入後複製這是我們所有句法糖塗層真正發光的地方。當您需要時,這是非常可讀,易於理解且易於改變的需求!簡而言之,我們創建了一個新的“藥水”表示,並將其保存在實際列表中。public delegate void SaveDelegate(object sender, EventArgs args); public static event SaveDelegate SaveEvent;
登入後複製創建一個級別的主對象
首先,一小部分準備工作。在我們現有的項目中,我們有一個全局變量,可以告訴我們是否正在加載場景。但是,我們沒有這樣的變量來告訴我們是否使用門過渡。我們希望當我們返回上一個房間時,所有掉落的對象仍然存在,即使我們沒有在兩者之間的任何位置保存/加載遊戲。 為此
在TransitionScript中>
public delegate void SaveDelegate(object sender, EventArgs args);
登入後複製登入後複製登入後複製登入後複製登入後複製我們已經準備好製作一個正常工作的levelmaster對象。
>>現在,我們只需要讀取列表並在加載遊戲時從它們中產生對象。這就是級別主體對象所做的。讓我們創建一個新腳本,並將其稱為public event SaveDelegate SaveEvent;
登入後複製登入後複製登入後複製登入後複製levelmaster
:> 這是很多代碼,所以讓我們將其分解。
>>//In PotionDroppable's Start or Awake function: GlobalObject.Instance.SaveEvent += SaveFunction; //In PotionDroppable's OnDestroy() function: GlobalObject.Instance.SaveEvent -= SaveFunction; //[...] public void SaveFunction (object sender, EventArgs args) { //Here is code that saves this instance of an object. }
登入後複製登入後複製如果我們
是加載場景,我們需要獲取我們的本地副本保存的對象列表(只是為了在重複訪問GlobalControl,
>和 的重複訪問時節省一些性能使語法更可讀)。 接下來,我們只需遍歷列表,並在其中催生所有藥水對象。產卵的確切語法基本上是實例化方法過載之一。我們必須將實例化方法的結果投入到> gameObject(由於某種原因,默認返回類型是簡單的對象),以便我們可以訪問其轉換並更改其位置。 >這是對象產生的地方:如果您需要在產卵時間更改任何其他值,那麼這是這樣做的地方。 >
我們需要將我們的級別主體放在每個場景中,並為其分配有效的預製:>
>現在我們只缺少一個關鍵作品:我們需要實際啟動活動,將列表序列化為硬盤驅動器並從中讀取。我們將在GlobalControl中的現有保存和加載功能中簡單地做到這一點:這似乎也有很多代碼,但是其中大多數已經存在。 (如果您遵循我以前的教程,您將識別二進制序列化命令;這裡唯一的新事物是FiresaveEvent函數,還有一個保存我們列表的附加文件。就是這樣!
>初始測試
如果您現在運行項目,則每次點擊> f5
andf9 >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>這樣)。[Serializable] public class SavedDroppablePotion { public float PositionX, PositionY, PositionZ; } [Serializable] public class SavedDroppableSword { public float PositionX, PositionY, PositionZ; }
登入後複製登入後複製但是,還有一個問題要解決:我們沒有保存劍。
這僅僅是為了演示如何在建立類似基礎的基礎後向項目中添加新的可保存的對象。
擴展系統
>因此,假設您已經有了一個新的對象覆蓋系統,就像我們已經對劍對象所做的一樣。它們目前的交互不多(基本物理學之外),因此我們需要編寫一個類似於藥水的腳本,這將使我們能夠“撿起”劍並使其正確保存。
>當前要產生的劍的預製可以在資產> prefabs文件夾中找到。
>讓它起作用。轉到資產>腳本>拾音器,在那裡您會看到
potiondroppable
腳本。旁邊,創建一個新的SwordDroppoppable腳本:public delegate void SaveDelegate(object sender, EventArgs args);
登入後複製登入後複製登入後複製登入後複製登入後複製不要忘記“可相互作用”的接口實現。非常重要的是:如果沒有它,您的劍將不會被攝像機射線廣播所識別,並且將保持不可分割效果。另外,請仔細檢查劍前是否屬於項目層。否則,Raycast將再次忽略它。現在,將此腳本添加到劍前的第一個孩子(實際上具有網狀渲染器和其他組件):
>現在,我們需要產生它們。在級別的大師中,在我們的循環下產生了藥水:
public event SaveDelegate SaveEvent;
登入後複製登入後複製登入後複製登入後複製…就是這樣。每當您需要保存的新項目類型時:
- 添加Serializables類
- 創建訂閱以保存事件 的項目腳本
- 在級別主持人中添加實例化邏輯。 >
結論
>目前,系統很粗糙:硬盤上有多個保存文件,對象的旋轉未保存(劍,玩家等),並且在場景過渡期間定位播放器的邏輯(但沒有)加載)有點古怪。
一旦實心系統到位,這些現在都是要解決的小問題,我邀請您嘗試修改本教程和完成的項目,以查看您是否可以改善系統。>示例
項目有很大不同。
如所承諾的,這是完成的項目,如果您需要參考,或者是因為您被卡在某個地方。根據本教程的說明和相同的命名計劃,將實現保存系統。下載完成的項目:
Project GitHub頁面
項目zip下載
>在Unity中掌握保存和加載功能的常見問題(常見問題解答)5
>在Unity 5中實現保存系統的最佳方法是什麼? PlayerPrefs是一種在遊戲會話之間存儲和檢索數據的簡單方法。它使您可以以整數,浮點和字符串的形式保存和加載數據。但是,重要的是要注意,PlayerPrefs不安全,不應用於敏感數據。對於更複雜或安全的數據,您可能需要考慮使用二進制格式或JSON Serialializer。在Unity 5中,可以使用PlayerPrefs,JSON序列化或二進制格式來實現。 PlayerPrefs是最簡單的方法,允許您保存和加載整數,浮點和字符串。 JSON序列化更為複雜,但可以提高靈活性和安全性。二進制格式是最安全的方法,但也是最複雜的方法。
>執行順序如何影響Unity 5?
> >如何在Unity 5?
中保護保存數據5可以通過使用二進制格式或加密來實現。二進制格式將您的數據轉換為不容易讀取的二進制格式。加密通過以一種只能用特定鍵來解碼的方式來編碼您的數據來添加額外的安全性。>
>在Unity 5中使用PlayerPrefs用於保存和加載功能的局限性是什麼? 🎜>雖然PlayerPrefs是在Unity 5中實現和加載功能的一種簡單便捷的方法,但它具有多個限制。首先,它僅支持整數,浮子和字符串。其次,它不安全,很容易被操縱。最後,playerPrefs具有尺寸限制,這對於具有大量數據的遊戲可能是一個問題。 >我如何保存和加載Unity 5?保存和加載中的複雜數據結構使用JSON序列化或二進制格式可以實現Unity 5中的複雜數據結構。 JSON序列化使您可以將復雜的數據結構轉換為可以輕鬆保存和加載的字符串格式。二進制格式是一種更安全的方法,可將您的數據轉換為二進制格式。 >我可以在Unity 5中的不同平台上保存和加載數據嗎?跨平台兼容性。例如,playerpRefs是跨平台兼容的,但是二進制格式可能並非在所有平台上兼容。
>我如何在Unity 5?
中加載問題的問題對問題進行故障排除。可以通過檢查腳本的執行順序,確保您的數據正確序列化或格式化並進行測試,從而在Unity 5中保存和加載功能。您打算在平台上發布的遊戲。可以通過最大程度地減少保存和加載的數據量,使用有效的數據結構,並確保您的腳本被良好地實現。
如何實現Unity中的AutoSave功能5?
可以通過創建一個腳本來自動保存遊戲的腳本,以定期或在特定事件中自動保存您的遊戲,可以在Unity 5中實現AutoSave功能。該腳本應使用相同的方法來保存數據與您的手動保存系統。
>
以上是掌握Unity中的保存和加載功能5的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱門文章

熱門文章

熱門文章標籤

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)