在《火拼24》的精彩游戲世界里,每一關(guān)的突破都凝聚著玩家的智慧與努力。然而,如何確保這些來之不易的闖關(guān)進度不會因設(shè)備更換或意外情況而丟失,成為了眾多玩家關(guān)注的焦點。
別擔心!在本節(jié)教程里,我們將為大家深度揭秘一項超實用的強大功能——基于 CRUD Save 打造的游戲闖關(guān)進度云端存檔,讓玩家們能安心暢玩,闖關(guān)進度永不丟失!
教程視頻
項目工程獲取與學習指引
1. 初始項目工程下載
倉庫地址:
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson3-start
分支名稱:lesson3-start 分支
分支說明:請先下載 lesson3-start 分支的項目工程,該分支是本節(jié)學習的起點。
倉庫地址:
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson3-end
分支名稱:lesson3-end 分支
分支說明:lesson3-end 分支包含本節(jié)所有功能的完整實現(xiàn)代碼,建議在學習完成后參考或用于調(diào)試對照。
可以在命令行窗口中直接輸入 Git 命令拉取項目工程到本地,也可以借助其它的可視化工具(如 Sourcetree)將倉庫克隆到本地。
例如,輸入以下命令即可拉取名為 lesson3-start 的分支對應(yīng)的項目工程:git clone -b lesson3-start https://cnb.cool/unity/uos/Rush24Tutorial.git
教程學習大綱
1. 項目的準備工作
2. 分析:原有的本地文件存儲的方式保存闖關(guān)進度
3. 實現(xiàn):使用 CRUD-Save 方式保存闖關(guān)進度
4. 自動云存檔功能(AutoSave)
教程操作步驟
接下來我們要開始本節(jié)課的學習啦!
1. 項目的準備工作1.1 下載并打開項目工程
請先通過上面提供的 git 倉庫鏈接,下載初始狀態(tài)(lesson3-start 分支)的項目工程。
然后通過 Unity Hub,打開剛剛下載好的項目工程。在教程中,我們是使用Unity 2022.3.42 f1c1版本來打開項目工程的,該教程同樣適用于團結(jié)引擎,請大家自行選擇想要使用的版本來開始你的學習。
打開項目工程以后,首先確保你的項目已經(jīng)綁定了第一章節(jié)教程中設(shè)置過的同一個 UOS App。
1.2 開通 CRUD-Save 服務(wù)并安裝 SDK
在 UOS Launcher 的下拉服務(wù)窗口列表中,找到「CRUD-Save」,點擊「Enable」開啟服務(wù)。
然后點擊「Install SDK」,安裝 CRUD-Save SDK。
2.分析:原有的本地文件存儲的方式保存闖關(guān)進度
在原有代碼中,我們是通過 Unity 提供的 Application.persistentDataPath(用于獲取持久化數(shù)據(jù)存儲路徑的接口),將闖關(guān)進度存儲于該路徑下的本地文件 stage_progress.dat 中的。
接下來,我們首先將分析這種基于本地文件存儲的傳統(tǒng)存檔方式的實現(xiàn)原理,隨后再將存檔功能的實現(xiàn)方案調(diào)整為基于 CRUD-Save 的云存檔方式。
可以看到在 LoadGameData.cs 腳本中,加載完遠端 RemoteConfig 配置的數(shù)據(jù)后,會調(diào)用 UOSSave.cs 腳本中的 Init 方法來加載本地存檔的關(guān)卡數(shù)據(jù),最后才進入游戲的主場景。
namespace TwentyFour.Scripts.Gameplay.HomePage
{
public class LoadGameData : MonoBehaviour
{
//......
// Start is called before the first frame update
IEnumerator Init()
{
yield return StartCoroutine(InitRemoteConfig());
yield return StartCoroutine(InitStage());
yield return StartCoroutine(InitSave());
GameRouter.LoadHomeSceneFirst();
}
IEnumerator InitSave()
{
coverPageHintText.text = "正在...了解過去...";
UOSSave.Init();
yield break;
}
//......
}
}找到 Scripts/Features/Save 文件夾路徑下的 UOSSave.cs 腳本并打開。
打開 UOSSave.cs 腳本,它主要用來實現(xiàn)關(guān)卡進度的本地存儲和讀取,具體思路如下:
存儲關(guān)卡進度(SavePlayerProgress 方法):將關(guān)卡成績列表轉(zhuǎn)換為字符串(如 [1,0,0...] → "100..."),賦值給 scoreString 變量。然后調(diào)用 File.WriteAllText 方法,將數(shù)據(jù)寫入 Unity 提供的 Application.persistentDataPath 路徑下,并由用戶自定義的 stage_progress.dat 文件中。如果某一關(guān)卡闖關(guān)成功,我們將會使用「1」來表示,如果闖關(guān)沒通過的話,用默認的「0」來表示。
讀取關(guān)卡進度(FetchPlayerProgress 方法):從 stage_progress.dat 文件中讀取保存的字符串,再通過調(diào)用 ConvertStringToList 方法,將字符串類型的關(guān)卡進度轉(zhuǎn)換為集合列表,恢復(fù)為關(guān)卡數(shù)據(jù)。最后通過 StageManager.cs 腳本,來加載實際的關(guān)卡進度。代碼中可以添加一行 Log:打印輸出下本地存儲的關(guān)卡進度信息。
初始化流程(Init 方法):游戲啟動時會檢查存檔文件是否存在,有存檔則加載關(guān)卡進度,無存檔則初始化空的闖關(guān)進度,也就是從第一關(guān)開始來解鎖。
namespace TwentyFour.Scripts.Features.Save
{
public class UOSSave
{
private static string SaveFilePath => Path.Combine(Application.persistentDataPath, "stage_progress.dat");
static List
ConvertStringToList(string str) { List
list = new List
(); foreach (char c in str) { // 將字符轉(zhuǎn)換為整數(shù)并添加到列表中 int number = int.Parse(c.ToString()); list.Add(number); } return list; } public static void Init() { if (File.Exists(SaveFilePath)) { FetchPlayerProgress(); } else { Logger.Log("not found existed score save"); StageManager.LoadEmptyStageScore(); } } private static void FetchPlayerProgress() { try { string scores = File.ReadAllText(SaveFilePath); Logger.Log("本地存儲的關(guān)卡進度為:" + scores); StageManager.LoadStageScores(ConvertStringToList(scores)); } catch (Exception e) { Logger.LogError($"Failed to load player progress: {e.Message}"); StageManager.LoadEmptyStageScore(); } } public static void SavePlayerProgress(List
scores) { try { string scoreString = string.Join("", scores); File.WriteAllText(SaveFilePath, scoreString); } catch (Exception e) { Logger.LogError($"Failed to save player progress: {e.Message}"); } } public static void Dispose() { // 如果需要清理資源可以在這里實現(xiàn) } } }
2.2 運行游戲,查看本地存檔文件中的數(shù)據(jù)
運行游戲,進入「闖關(guān)」頁面后,可以看到打印輸出的 Log 信息:1100,已經(jīng)通過的關(guān)卡就是數(shù)字「1」表示的第一關(guān)和第二關(guān),未通過的關(guān)卡就是數(shù)字「0」表示的第三關(guān)和第四關(guān)。
進入 Application.persistentDataPath 路徑對應(yīng)的文件夾,可以看到路徑下的 stage_progress.dat 存檔文件。
但是,如果大家此時更換了一臺設(shè)備,運行你的當前項目工程的話,由于新設(shè)備路徑中沒有存檔文件 stage_progress.dat,運行后在 Game 窗口中會看到每一關(guān)都是未被解鎖的狀態(tài)。
3. 實現(xiàn):使用 CRUD-Save 方式保存闖關(guān)進度
我們接下來將實現(xiàn):基于 CRUD-Save 打造的游戲闖關(guān)進度云端存檔功能,它能實現(xiàn)當前登錄用戶闖關(guān)進度的云端保存,讓用戶更換設(shè)備后再次進入仍可無縫銜接。
3.1 什么是 CRUD-Save
CRUD-Save 是 UOS 提供的全面而專業(yè)的玩家數(shù)據(jù)存儲、檢索及管理服務(wù)。開發(fā)者能夠極為便捷地為廣大游戲玩家打造出一個:跨越不同平臺與設(shè)備的、安全且高度可用的游戲存檔系統(tǒng)。
這一服務(wù)不僅確保了玩家能夠在任何時間、任何地點,無縫地繼續(xù)他們的游戲進程,而且通過嚴格的數(shù)據(jù)安全保障措施,讓玩家的游戲數(shù)據(jù)始終處于嚴密的保護之下。同時,其高可用性的設(shè)計也保證了玩家數(shù)據(jù)的實時同步與持久存儲,為玩家?guī)砹烁恿鲿场⒎€(wěn)定的游戲體驗。
將原來的 Init 方法,修改為使用 async 修飾的異步方法。然后方法中調(diào)用 SDK 提供的 InitializeAsync 方法,來初始化 CRUD-Save SDK,確保后續(xù)有關(guān)云存儲的操作可以正常進行。并使用 try...catch... 機制,捕獲客戶端和服務(wù)端遇到的異常。
using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using Logger = TwentyFour.Scripts.Utilities.Logger;
using TwentyFour.Scripts.Gameplay.GameMode.StageMode;
using System.Linq;
using Unity.UOS.CloudSave;
using Unity.UOS.CloudSave.Exception;
using Unity.UOS.CloudSave.Model.Files;
namespace TwentyFour.Scripts.Features.Save
{
public class UOSSave
{
//......
public static async void Init()
{
try
{
// 異步初始化 CRUD-Save SDK
await CloudSaveSDK.InitializeAsync();
}
catch (CloudSaveClientException e)
{
Debug.Log($"clientEx: {e.Message}");
}
catch (CloudSaveServerException e)
{
Debug.Log($"serverEx: {e.Message}");
}
if (File.Exists(SaveFilePath))
{
FetchPlayerProgress();
}
else
{
Logger.Log("not found existed score save");
StageManager.LoadEmptyStageScore();
}
}
}3.3 修改存檔方法 SavePlayerProgress
修改保存玩家存檔進度的方法(SavePlayerProgress),實現(xiàn)將玩家的闖關(guān)進度存檔到云端,該方法也需要添加 async 修飾符:
public static async void SavePlayerProgress(List
scores) { //...... }
然后根據(jù)是否創(chuàng)建過云存檔文件,分為以下兩種情況來處理:
3.3.1 首次創(chuàng)建存檔文件
如果當前沒有存檔 ID(即 _stageScoresSaveId 為空),說明還沒有創(chuàng)建過存檔。我們將調(diào)用 SDK 提供的 CreateAsync 方法,來創(chuàng)建一個新的云端存檔來保存闖關(guān)數(shù)據(jù)。
在 CreateAsync 方法中我們通過字節(jié)數(shù)組的方式來創(chuàng)建一個存檔,傳入三個參數(shù):
存檔名稱:使用變量 name 的值;
字節(jié)數(shù)組類型的存檔文件:將闖關(guān)成績列表 scores 序列化為字節(jié)數(shù)組,賦值給變量 bytes;
存檔選項:傳入 CreateOptions 類型的變量,設(shè)置存檔所屬的命名空間(Namespace);
方法的返回值:表示當前存檔 ID,賦值給了變量 _stageScoresSaveId ;
如果在創(chuàng)建存檔過程中,出現(xiàn)客戶端異常(如網(wǎng)絡(luò)問題、參數(shù)錯誤等),或者服務(wù)端異常(如服務(wù)器故障、權(quán)限問題等),會捕獲并記錄錯誤日志。
namespace TwentyFour.Scripts.Features.Save
{
public class UOSSave
{
private static string _stageScoresSaveId;
private const string SAVE_NS_STAGE_SCORES = "StageScores";
//......
public static async void SavePlayerProgress(List
scores) { byte[] bytes = SerializeList.Serialize(scores); // 如果當前沒有存檔ID,說明還沒有創(chuàng)建過存檔 if (string.IsNullOrEmpty(_stageScoresSaveId)) { string name = SAVE_NS_STAGE_SCORES; // 存檔名稱 try { // 創(chuàng)建存檔時的選項,指定命名空間 CreateOptions options = new CreateOptions () { Namespace = SAVE_NS_STAGE_SCORES }; // 異步創(chuàng)建新存檔,并獲取存檔ID _stageScoresSaveId = await CloudSaveSDK.Instance.Files.CreateAsync(name, bytes, options); } // 捕獲客戶端異常并記錄錯誤日志 catch (CloudSaveClientException e) { Logger.LogError($"failed to save file, name {name}, clientEx: {e.Message}"); } // 捕獲服務(wù)端異常并記錄錯誤日志 catch (CloudSaveServerException e) { Logger.LogError($"failed to save file, name {name}, serverEx: {e.Message}"); } } } } }
3.3.2 更新已創(chuàng)建的存檔文件
第二種情況是:當存檔 ID 不為空,也就是已經(jīng)有了存檔文件的情況下,我們只需要更新同一個存檔文件即可。
調(diào)用 UpdateAsync 方法來更新存檔文件,方法中傳入兩個參數(shù):
已創(chuàng)建的存檔 ID:使用之前 _stageScoresSaveId 變量保存的值;
更新存檔選項:傳入 UpdateOptions 類型的變量,指定要更新的文件內(nèi)容(FileBytes),更新文件的方式為ByFileBytes;
同樣的使用 try...catch... 來捕獲,更新存檔的過程中出現(xiàn)的客戶端或者服務(wù)端的異常信息。
public static async void SavePlayerProgress(List
scores) { byte[] bytes = SerializeList.Serialize(scores); // 如果當前沒有存檔ID,說明還沒有創(chuàng)建過存檔 if (string.IsNullOrEmpty(_stageScoresSaveId)) { //...... } else { // 更新已有存檔 try { // 更新存檔選項, 可以通過該方法更新存檔文件,也可以僅更新存檔配置 UpdateOptions options = new UpdateOptions() { File = new Unity.UOS.CloudSave.Model.Files.FileOptions() { FileBytes = bytes, UpdateFileWay = UpdateFileWay.ByFileBytes } }; await CloudSaveSDK.Instance.Files.UpdateAsync(_stageScoresSaveId, options); } catch (CloudSaveClientException e) { Logger.LogError($"failed to update file, saveId {_stageScoresSaveId}, clientEx: {e.Message}"); } catch (CloudSaveServerException e) { Logger.LogError($"failed to update file, saveId {_stageScoresSaveId}, serverEx: {e.Message}"); } } }
3.3.3 運行游戲,查看創(chuàng)建的存檔文件
運行游戲進行測試,比如完成第一關(guān)卡闖關(guān)后,進入 CRUD-Save 的「存檔管理」頁面,可以看到已經(jīng)有一條存檔信息了。
存檔文件名、命名空間,都是代碼中傳入的變量名 StageScores。
然后再次運行第二關(guān)、第三關(guān)的游戲進行測試,可以看到闖關(guān)進度更新時,CRUD-Save 的「存檔管理」頁面會實時更新存檔文件的信息。
但是,如果我們現(xiàn)在停止游戲后,再次重新運行的話,發(fā)現(xiàn)「闖關(guān)」界面的進度并沒有更新,因為我們還沒有從云存檔中讀取闖關(guān)的進度。
3.4 修改讀取游戲存檔進度的方法
接下來,我們就修改 FetchPlayerProgress 方法的代碼,實現(xiàn)從存檔文件中獲取到玩家的闖關(guān)進度,并更新到 UI 界面上。
首先,調(diào)用 SDK 封裝的 LoadBytesAsync 方法,通過用戶的存檔 ID(_stageScoresSaveId)異步獲取云端存檔文件的內(nèi)容,并以字節(jié)數(shù)組(bytes)的形式返回。
然后,將獲取到的字節(jié)數(shù)組(bytes)通過反序列化操作,轉(zhuǎn)換為闖關(guān)進度列表,并存儲在變量 scores 中。接著,調(diào)用 StageManager.cs 腳本中封裝的 LoadStageScores 方法,將闖關(guān)進度數(shù)據(jù)加載到游戲的闖關(guān)界面,實現(xiàn)玩家進度的恢復(fù)。
整個加載過程中,同樣的使用 try...catch... 結(jié)構(gòu)分別捕獲客戶端和服務(wù)端的異常,并通過日志詳細記錄異常信息,以便于后續(xù)排查和調(diào)試。
private static async void FetchPlayerProgress()
{
try
{
byte[] bytes = await CloudSaveSDK.Instance.Files.LoadBytesAsync(_stageScoresSaveId);
var scores = SerializeList.Deserialize
(bytes); StageManager.LoadStageScores(scores); } catch (CloudSaveClientException e) { Logger.LogError($"failed to load file, saveId {_stageScoresSaveId}, clientEx: {e.Message}"); throw; } catch (CloudSaveServerException e) { Logger.LogError($"failed to load file, saveId {_stageScoresSaveId}, serverEx: {e.Message}"); throw; } }
3.5 從云端加載存儲的闖關(guān)進度數(shù)據(jù)
在初始化 Init 方法中,實現(xiàn) CRUD-Save SDK 初始化后,繼續(xù)添加代碼,實現(xiàn)從云端加載存儲的闖關(guān)進度數(shù)據(jù)。
首先,調(diào)用 SDK 提供的 ListAllAsync 方法來獲取云端所有存檔文件。該方法需要傳入一個 ListOptions 類型的參數(shù),其中可以指定存檔所屬的命名空間、角色ID、存檔模式、是否包含封面等選項。并將命名空間設(shè)置為之前定義的常量 SAVE_NS_STAGE_SCORES,以便只查詢與關(guān)卡進度相關(guān)的存檔文件。
判斷下如果返回的存檔文件列表(saveItems)不為空,說明云端已經(jīng)存在相關(guān)的存檔文件。此時,代碼會獲取列表中第一條存檔的 SaveId,并將其保存到變量 _stageScoresSaveId 中。接著,調(diào)用之前封裝的 FetchPlayerProgress 方法,加載該存檔 ID 對應(yīng)的存檔數(shù)據(jù),并在闖關(guān)界面上進行展示。
如果返回的存檔文件列表為空,說明當前沒有任何存檔信息。此時會輸出日志提示,并調(diào)用 StageManager.cs 腳本中的 LoadEmptyStageScore 方法,從第一關(guān)開始初始化游戲進度,讓玩家從頭開始闖關(guān)。
public class UOSSave
{
//......
public static async void Init()
{
try
{
await CloudSaveSDK.InitializeAsync();
var options = new ListOptions()
{
Namespaces = new List
() { SAVE_NS_STAGE_SCORES }, }; var saveItems = await CloudSaveSDK.Instance.Files.ListAllAsync(options); if (saveItems.Any()) { _stageScoresSaveId = saveItems[0].SaveId; FetchPlayerProgress(); } else { Logger.Log("not found existed score save"); StageManager.LoadEmptyStageScore(); } } catch (CloudSaveClientException e) { Debug.Log($"clientEx: {e.Message}"); } catch (CloudSaveServerException e) { Debug.Log($"serverEx: {e.Message}"); } } //...... }
運行游戲后進行測試,看到闖關(guān)界面上的 UI 已經(jīng)實時更新了,說明成功加載到了云端存檔文件中的數(shù)據(jù)。
3.6 清空存檔數(shù)據(jù)
當玩家退出登錄、切換賬號時,如果該用戶沒有任何存檔數(shù)據(jù),需要清空當前登錄用戶的存檔 ID 變量(_stageScoresSaveId),確保后續(xù)操作不會再關(guān)聯(lián)到之前的存檔。
public static async void Init()
{
try
{
await CloudSaveSDK.InitializeAsync();
var options = new ListOptions()
{
Namespaces = new List
() { SAVE_NS_STAGE_SCORES }, }; var saveItems = await CloudSaveSDK.Instance.Files.ListAllAsync(options); if (saveItems.Any()) { _stageScoresSaveId = saveItems[0].SaveId; FetchPlayerProgress(); } else { _stageScoresSaveId = string.Empty; Logger.Log("not found existed score save"); StageManager.LoadEmptyStageScore(); } } //...... }
4. 自動云存檔功能(AutoSave)
除了通過 CRUD-Save SDK 提供的 CreateAsync 方法來手動創(chuàng)建云存檔文件外,UOS 還提供了自動云存檔功能(AutoSave)。
4.1 自動云存檔的作用
自動云存檔會在本地指定路徑定期保存存檔文件的同時,自動將該文件同步上傳到云端。這樣,用戶既能在本地快速訪問和恢復(fù)存檔,也能確保數(shù)據(jù)安全地備份在云端,防止因本地數(shù)據(jù)丟失而造成損失。
自動云存檔適合需要頻繁保存和同步進度的場景,開發(fā)者只需簡單配置(如文件名、保存間隔、沖突策略等),即可實現(xiàn)本地與云端的雙重存檔。
4.2 自動云存檔的示例代碼參考
實現(xiàn)方式可以參考: CRUD-Save SDK 提供的示例腳本 AutoSaveSample.cs 中代碼的用法。
AutoSaveSample.cs 腳本演示了如何在 Unity 項目中集成 CRUD-Save 的自動云存檔功能,實現(xiàn)本地文件定時的自動上傳至云端。
在初始化 CRUD-Save SDK 之后,可以先使用 UOS 提供的 Passport 登錄(即 Passport Login 方式),或者外部登錄的方式(ExternalLogin),來獲取用戶的認證 Token。在當前示例代碼中,我們暫時先以外部登錄的方式(ExternalLogin)來實現(xiàn)。
然后調(diào)用 AutoSaveManager.cs 腳本封裝的EnableAutoSave 方法實現(xiàn)自動云存檔,傳入 AutoSaveOptions 類型的配置(指定如文件名、自動保存文件間隔、沖突策略、本地文件存儲路徑等),開啟自動云存檔功能。此后,指定的本地文件會定期自動同步到云端。
協(xié)程方法 PerformFileOperations 是我們給出的一個本地文件的操作演示。
namespace Unity.UOS.CloudSave.Samples.BasicExample
{
public class AutoSaveSample : MonoBehaviour
{
public string userId;
private string _personaId = "test-persona-id";
private async void Start()
{
// 初始化 sdk instance
try
{
// 如果安裝了Uos Launcher 使用Uos Launcher關(guān)聯(lián)的Uos App初始化SDK
await CloudSaveSDK.InitializeAsync();
// 如果需要使用其他 UOS APP,可傳入一對AppId, AppSecret初始化SDK
// await CloudSaveSDK.InitializeAsync(appId, appSecret);
}
catch (CloudSaveClientException e)
{
Debug.LogErrorFormat("failed to initialize sdk, clientEx: {0}", e);
throw;
}
catch (CloudSaveServerException e)
{
Debug.LogErrorFormat("failed to initialize sdk, serverEx: {0}", e);
throw;
}
// 初始化AuthTokenManager中的user token, personaId為選填項
await AuthTokenManager.ExternalLogin(userId, _personaId);
await AutoSaveManager.Instance.EnableAutoSave(new AutoSaveOptions
{
FileName = "autoSave",
Interval = 120,
ConflictStrategy = ConflictStrategy.LastWrite,
BasePath = Application.persistentDataPath
});
StartCoroutine(PerformFileOperations(AutoSaveManager.Instance.Path));
}
private IEnumerator PerformFileOperations(string filePath)
{
yield return new WaitForSeconds(3);
Debug.LogFormat("Auto load file exists in {0}? {1}", filePath, File.Exists(filePath));
File.WriteAllText(filePath, "Created file");
Debug.Log("Created file at: " + filePath);
yield return new WaitForSeconds(1);
File.AppendAllText(filePath, "Appended file");
Debug.Log("Appended file at: " + filePath);
yield return new WaitForSeconds(1);
File.WriteAllText(filePath, "Overwritten file");
Debug.Log("Overwritten file at: " + filePath);
yield return new WaitForSeconds(1);
File.WriteAllText(filePath, "Test manually flush");
Debug.Log("Test file at: " + filePath);
yield return AutoSaveManager.Instance.Flush();
}
}
}4.3 運行測試示例代碼
接著,我們可以測試下上面的腳本!大家先自行創(chuàng)建一個新的項目工程,綁定好創(chuàng)建的 UOS App,開通 CRUD-Save 服務(wù)并安裝 SDK。
然后在場景中創(chuàng)建一個空對象,可以暫時命名為 AutoSaveSample,將 AutoSaveSample.cs 腳本掛載給空對象,并為 Inspector 面板上的 userId 變量賦值,當前先暫時設(shè)置為:externalLogin_userId。
然后運行項目,在 Console 控制臺可以看到相關(guān)的日志信息:說明存檔文件自動上傳成功了。
進入「CRUD Save」的「存檔管理」頁面,可以看到已經(jīng)自動上傳的文件名為「autoSave」的存檔文件:
在腳本中設(shè)置的 Application.persistentDataPath 路徑下,可以看到同時也有一份存檔文件的。當然,本地存檔的路徑,大家可以在腳本中自行設(shè)置的:
4.4 本地存檔和云存檔的沖突解決
當本地存檔和云端存檔因文件更新時間不一致發(fā)生沖突時,我們提供了以下三種沖突解決策略,大家可根據(jù)實際需求選擇適合的方式:
public enum ConflictStrategy
{
// 默認,沖突時報錯:"本地存檔和云存檔存在沖突,需要手動解決。"
Default = 0,
// 拋棄本地存檔,保留云存檔
DiscardLocal = 1,
// 保留最后寫入存檔
LastWrite = 3
}Default(默認)
含義:當本地存檔和云存檔更新時間不一致發(fā)生沖突時,系統(tǒng)會報錯,提示“本地存檔和云存檔存在沖突,需要手動解決”。
適用場景:適合對存檔一致性要求很高的場景,需要開發(fā)者或用戶手動選擇用哪個存檔,防止數(shù)據(jù)丟失或覆蓋。
DiscardLocal(拋棄本地存檔)
含義:當發(fā)生沖突時,直接丟棄本地存檔,保留云端存檔的數(shù)據(jù)。
適用場景:適合以云端數(shù)據(jù)為主的場景,比如多端同步,或者認為云端數(shù)據(jù)更權(quán)威、更安全的情況。
LastWrite(保留最后寫入存檔)
含義:無論是本地還是云端,誰最后寫入,誰的數(shù)據(jù)就被保留(即“最后寫入優(yōu)先”)。
適用場景:適合需要自動解決沖突、以最新操作為準的場景,比如頻繁切換設(shè)備、多人協(xié)作但只需最新進度的游戲。
下節(jié)教程預(yù)告
教程主題——《火拼24》系列教程四:微信小游戲CDN資源部署
在《火拼24》系列教程第四章中,我們將聚焦于微信小游戲的 CDN 資源部署。教程將詳細介紹如何將游戲資源進行打包,并上傳到 CDN 平臺。通過本篇內(nèi)容,你將掌握微信小游戲上線前資源部署的完整流程,為游戲的流暢運行和優(yōu)質(zhì)體驗提供有力保障。
小貼士:為方便大家提前學習,教程第四章節(jié)的分支代碼已同步更新,可提前下載查閱或本地調(diào)試。
教程四:初始項目工程(供學習參考)
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson4-start
教程四:完整示例工程參考(可直接運行)
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson4-end
記得鎖定更新,別錯過每一步關(guān)鍵指南!
Unity Online Services (UOS) 是一個專為游戲開發(fā)者設(shè)計的一站式游戲云服務(wù)平臺,提供覆蓋游戲全生命周期的開發(fā)、運營和推廣支持。
了解更多 UOS 相關(guān)信息:
官網(wǎng):https://uos.unity.cn
技術(shù)交流 QQ 群:823878269
Unity 官方微信
第一時間了解Unity引擎動向,學習進階開發(fā)技能
![]()
每一個“點贊”、“在看”,都是我們前進的動力
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.