夜夜躁很很躁日日躁麻豆,精品人妻无码,制服丝袜国产精品,成人免费看www网址入口

網(wǎng)易首頁 > 網(wǎng)易號(hào) > 正文 申請(qǐng)入駐

《火拼24》系列教程三:游戲闖關(guān)進(jìn)度的云端存檔

0
分享至

在《火拼24》的精彩游戲世界里,每一關(guān)的突破都凝聚著玩家的智慧與努力。然而,如何確保這些來之不易的闖關(guān)進(jìn)度不會(huì)因設(shè)備更換或意外情況而丟失,成為了眾多玩家關(guān)注的焦點(diǎn)。

別擔(dān)心!在本節(jié)教程里,我們將為大家深度揭秘一項(xiàng)超實(shí)用的強(qiáng)大功能——基于 CRUD Save 打造的游戲闖關(guān)進(jìn)度云端存檔,讓玩家們能安心暢玩,闖關(guān)進(jìn)度永不丟失!

教程視頻

項(xiàng)目工程獲取與學(xué)習(xí)指引

1. 初始項(xiàng)目工程下載

  • 倉庫地址:

https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson3-start

  • 分支名稱:lesson3-start 分支

  • 分支說明:請(qǐng)先下載 lesson3-start 分支的項(xiàng)目工程,該分支是本節(jié)學(xué)習(xí)的起點(diǎn)。

2.完整示例工程參考
  • 倉庫地址:

https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson3-end

  • 分支名稱:lesson3-end 分支

  • 分支說明:lesson3-end 分支包含本節(jié)所有功能的完整實(shí)現(xiàn)代碼,建議在學(xué)習(xí)完成后參考或用于調(diào)試對(duì)照。

3.將項(xiàng)目工程克隆到本地

可以在命令行窗口中直接輸入 Git 命令拉取項(xiàng)目工程到本地,也可以借助其它的可視化工具(如 Sourcetree)將倉庫克隆到本地。

例如,輸入以下命令即可拉取名為 lesson3-start 的分支對(duì)應(yīng)的項(xiàng)目工程:git clone -b lesson3-start https://cnb.cool/unity/uos/Rush24Tutorial.git

教程學(xué)習(xí)大綱

1. 項(xiàng)目的準(zhǔn)備工作

2. 分析:原有的本地文件存儲(chǔ)的方式保存闖關(guān)進(jìn)度

3. 實(shí)現(xiàn):使用 CRUD-Save 方式保存闖關(guān)進(jìn)度

4. 自動(dòng)云存檔功能(AutoSave)

教程操作步驟

接下來我們要開始本節(jié)課的學(xué)習(xí)啦!

1. 項(xiàng)目的準(zhǔn)備工作1.1 下載并打開項(xiàng)目工程

請(qǐng)先通過上面提供的 git 倉庫鏈接,下載初始狀態(tài)(lesson3-start 分支)的項(xiàng)目工程。

然后通過 Unity Hub,打開剛剛下載好的項(xiàng)目工程。在教程中,我們是使用Unity 2022.3.42 f1c1版本來打開項(xiàng)目工程的,該教程同樣適用于團(tuán)結(jié)引擎,請(qǐng)大家自行選擇想要使用的版本來開始你的學(xué)習(xí)。

打開項(xiàng)目工程以后,首先確保你的項(xiàng)目已經(jīng)綁定了第一章節(jié)教程中設(shè)置過的同一個(gè) UOS App。

1.2 開通 CRUD-Save 服務(wù)并安裝 SDK

在 UOS Launcher 的下拉服務(wù)窗口列表中,找到「CRUD-Save」,點(diǎn)擊「Enable」開啟服務(wù)。

然后點(diǎn)擊「Install SDK」,安裝 CRUD-Save SDK。

2.分析:原有的本地文件存儲(chǔ)的方式保存闖關(guān)進(jìn)度

在原有代碼中,我們是通過 Unity 提供的 Application.persistentDataPath(用于獲取持久化數(shù)據(jù)存儲(chǔ)路徑的接口),將闖關(guān)進(jìn)度存儲(chǔ)于該路徑下的本地文件 stage_progress.dat 中的。

接下來,我們首先將分析這種基于本地文件存儲(chǔ)的傳統(tǒng)存檔方式的實(shí)現(xiàn)原理,隨后再將存檔功能的實(shí)現(xiàn)方案調(diào)整為基于 CRUD-Save 的云存檔方式。

  • 可以看到在 LoadGameData.cs 腳本中,加載完遠(yuǎn)端 RemoteConfig 配置的數(shù)據(jù)后,會(huì)調(diào)用 UOSSave.cs 腳本中的 Init 方法來加載本地存檔的關(guān)卡數(shù)據(jù),最后才進(jìn)入游戲的主場(chǎng)景。

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 腳本并打開。

2.1 使用 File 類將闖關(guān)進(jìn)度存儲(chǔ)至本地文件中

打開 UOSSave.cs 腳本,它主要用來實(shí)現(xiàn)關(guān)卡進(jìn)度的本地存儲(chǔ)和讀取,具體思路如下:

  • 存儲(chǔ)關(guān)卡進(jìn)度(SavePlayerProgress 方法):將關(guān)卡成績(jī)列表轉(zhuǎn)換為字符串(如 [1,0,0...] → "100..."),賦值給 scoreString 變量。然后調(diào)用 File.WriteAllText 方法,將數(shù)據(jù)寫入 Unity 提供的 Application.persistentDataPath 路徑下,并由用戶自定義的 stage_progress.dat 文件中。如果某一關(guān)卡闖關(guān)成功,我們將會(huì)使用「1」來表示,如果闖關(guān)沒通過的話,用默認(rèn)的「0」來表示。

  • 讀取關(guān)卡進(jìn)度(FetchPlayerProgress 方法):從 stage_progress.dat 文件中讀取保存的字符串,再通過調(diào)用 ConvertStringToList 方法,將字符串類型的關(guān)卡進(jìn)度轉(zhuǎn)換為集合列表,恢復(fù)為關(guān)卡數(shù)據(jù)。最后通過 StageManager.cs 腳本,來加載實(shí)際的關(guān)卡進(jìn)度。代碼中可以添加一行 Log:打印輸出下本地存儲(chǔ)的關(guān)卡進(jìn)度信息。

  • 初始化流程(Init 方法):游戲啟動(dòng)時(shí)會(huì)檢查存檔文件是否存在,有存檔則加載關(guān)卡進(jìn)度,無存檔則初始化空的闖關(guān)進(jì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("本地存儲(chǔ)的關(guān)卡進(jì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()         {             // 如果需要清理資源可以在這里實(shí)現(xiàn)         }     } } 




2.2 運(yùn)行游戲,查看本地存檔文件中的數(shù)據(jù)

運(yùn)行游戲,進(jìn)入「闖關(guān)」頁面后,可以看到打印輸出的 Log 信息:1100,已經(jīng)通過的關(guān)卡就是數(shù)字「1」表示的第一關(guān)和第二關(guān),未通過的關(guān)卡就是數(shù)字「0」表示的第三關(guān)和第四關(guān)。

進(jìn)入 Application.persistentDataPath 路徑對(duì)應(yīng)的文件夾,可以看到路徑下的 stage_progress.dat 存檔文件。

但是,如果大家此時(shí)更換了一臺(tái)設(shè)備,運(yùn)行你的當(dāng)前項(xiàng)目工程的話,由于新設(shè)備路徑中沒有存檔文件 stage_progress.dat,運(yùn)行后在 Game 窗口中會(huì)看到每一關(guān)都是未被解鎖的狀態(tài)。

3. 實(shí)現(xiàn):使用 CRUD-Save 方式保存闖關(guān)進(jìn)度

我們接下來將實(shí)現(xiàn):基于 CRUD-Save 打造的游戲闖關(guān)進(jìn)度云端存檔功能,它能實(shí)現(xiàn)當(dāng)前登錄用戶闖關(guān)進(jìn)度的云端保存,讓用戶更換設(shè)備后再次進(jìn)入仍可無縫銜接。

3.1 什么是 CRUD-Save

  • CRUD-Save 是 UOS 提供的全面而專業(yè)的玩家數(shù)據(jù)存儲(chǔ)、檢索及管理服務(wù)。開發(fā)者能夠極為便捷地為廣大游戲玩家打造出一個(gè):跨越不同平臺(tái)與設(shè)備的、安全且高度可用的游戲存檔系統(tǒng)。

  • 這一服務(wù)不僅確保了玩家能夠在任何時(shí)間、任何地點(diǎn),無縫地繼續(xù)他們的游戲進(jìn)程,而且通過嚴(yán)格的數(shù)據(jù)安全保障措施,讓玩家的游戲數(shù)據(jù)始終處于嚴(yán)密的保護(hù)之下。同時(shí),其高可用性的設(shè)計(jì)也保證了玩家數(shù)據(jù)的實(shí)時(shí)同步與持久存儲(chǔ),為玩家?guī)砹烁恿鲿?、穩(wěn)定的游戲體驗(yàn)。

3.2 初始化 CRUD-Save SDK

將原來的 Init 方法,修改為使用 async 修飾的異步方法。然后方法中調(diào)用 SDK 提供的 InitializeAsync 方法,來初始化 CRUD-Save SDK,確保后續(xù)有關(guān)云存儲(chǔ)的操作可以正常進(jìn)行。并使用 try...catch... 機(jī)制,捕獲客戶端和服務(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

修改保存玩家存檔進(jìn)度的方法(SavePlayerProgress),實(shí)現(xiàn)將玩家的闖關(guān)進(jìn)度存檔到云端,該方法也需要添加 async 修飾符:

public static async void SavePlayerProgress(List

 scores) {     //......     } 

然后根據(jù)是否創(chuàng)建過云存檔文件,分為以下兩種情況來處理:

3.3.1 首次創(chuàng)建存檔文件

如果當(dāng)前沒有存檔 ID(即 _stageScoresSaveId 為空),說明還沒有創(chuàng)建過存檔。我們將調(diào)用 SDK 提供的 CreateAsync 方法,來創(chuàng)建一個(gè)新的云端存檔來保存闖關(guān)數(shù)據(jù)。

在 CreateAsync 方法中我們通過字節(jié)數(shù)組的方式來創(chuàng)建一個(gè)存檔,傳入三個(gè)參數(shù):

  • 存檔名稱:使用變量 name 的值;

  • 字節(jié)數(shù)組類型的存檔文件:將闖關(guān)成績(jī)列表 scores 序列化為字節(jié)數(shù)組,賦值給變量 bytes;

  • 存檔選項(xiàng):傳入 CreateOptions 類型的變量,設(shè)置存檔所屬的命名空間(Namespace);

  • 方法的返回值:表示當(dāng)前存檔 ID,賦值給了變量 _stageScoresSaveId ;

  • 如果在創(chuàng)建存檔過程中,出現(xiàn)客戶端異常(如網(wǎng)絡(luò)問題、參數(shù)錯(cuò)誤等),或者服務(wù)端異常(如服務(wù)器故障、權(quán)限問題等),會(huì)捕獲并記錄錯(cuò)誤日志。


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);             // 如果當(dāng)前沒有存檔ID,說明還沒有創(chuàng)建過存檔             if (string.IsNullOrEmpty(_stageScoresSaveId))             {                 string name = SAVE_NS_STAGE_SCORES; // 存檔名稱                 try                 {                     // 創(chuàng)建存檔時(shí)的選項(xiàng),指定命名空間                     CreateOptions  options = new CreateOptions ()                     {                         Namespace = SAVE_NS_STAGE_SCORES                     };                     // 異步創(chuàng)建新存檔,并獲取存檔ID                     _stageScoresSaveId = await CloudSaveSDK.Instance.Files.CreateAsync(name, bytes, options);                 }                 // 捕獲客戶端異常并記錄錯(cuò)誤日志                 catch (CloudSaveClientException e)                 {                     Logger.LogError($"failed to save file, name {name}, clientEx: {e.Message}");                 }                 // 捕獲服務(wù)端異常并記錄錯(cuò)誤日志                 catch (CloudSaveServerException e)                 {                     Logger.LogError($"failed to save file, name {name}, serverEx: {e.Message}");                 }             }         }     } } 

3.3.2 更新已創(chuàng)建的存檔文件

第二種情況是:當(dāng)存檔 ID 不為空,也就是已經(jīng)有了存檔文件的情況下,我們只需要更新同一個(gè)存檔文件即可。

調(diào)用 UpdateAsync 方法來更新存檔文件,方法中傳入兩個(gè)參數(shù):

  • 已創(chuàng)建的存檔 ID:使用之前 _stageScoresSaveId 變量保存的值;

  • 更新存檔選項(xiàng):傳入 UpdateOptions 類型的變量,指定要更新的文件內(nèi)容(FileBytes),更新文件的方式為ByFileBytes;

  • 同樣的使用 try...catch... 來捕獲,更新存檔的過程中出現(xiàn)的客戶端或者服務(wù)端的異常信息。


    public static async void SavePlayerProgress(List

 scores)     {         byte[] bytes = SerializeList.Serialize(scores);         // 如果當(dāng)前沒有存檔ID,說明還沒有創(chuàng)建過存檔         if (string.IsNullOrEmpty(_stageScoresSaveId))         {             //......         }         else         {             // 更新已有存檔             try             {                 // 更新存檔選項(xiàng), 可以通過該方法更新存檔文件,也可以僅更新存檔配置                 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 運(yùn)行游戲,查看創(chuàng)建的存檔文件

運(yùn)行游戲進(jìn)行測(cè)試,比如完成第一關(guān)卡闖關(guān)后,進(jìn)入 CRUD-Save 的「存檔管理」頁面,可以看到已經(jīng)有一條存檔信息了。

存檔文件名、命名空間,都是代碼中傳入的變量名 StageScores。

然后再次運(yùn)行第二關(guān)、第三關(guān)的游戲進(jìn)行測(cè)試,可以看到闖關(guān)進(jìn)度更新時(shí),CRUD-Save 的「存檔管理」頁面會(huì)實(shí)時(shí)更新存檔文件的信息。

但是,如果我們現(xiàn)在停止游戲后,再次重新運(yùn)行的話,發(fā)現(xiàn)「闖關(guān)」界面的進(jìn)度并沒有更新,因?yàn)槲覀冞€沒有從云存檔中讀取闖關(guān)的進(jìn)度。

3.4 修改讀取游戲存檔進(jìn)度的方法

接下來,我們就修改 FetchPlayerProgress 方法的代碼,實(shí)現(xiàn)從存檔文件中獲取到玩家的闖關(guān)進(jìn)度,并更新到 UI 界面上。

  • 首先,調(diào)用 SDK 封裝的 LoadBytesAsync 方法,通過用戶的存檔 ID(_stageScoresSaveId)異步獲取云端存檔文件的內(nèi)容,并以字節(jié)數(shù)組(bytes)的形式返回。

  • 然后,將獲取到的字節(jié)數(shù)組(bytes)通過反序列化操作,轉(zhuǎn)換為闖關(guān)進(jìn)度列表,并存儲(chǔ)在變量 scores 中。接著,調(diào)用 StageManager.cs 腳本中封裝的 LoadStageScores 方法,將闖關(guān)進(jìn)度數(shù)據(jù)加載到游戲的闖關(guān)界面,實(shí)現(xiàn)玩家進(jìn)度的恢復(fù)。

  • 整個(gè)加載過程中,同樣的使用 try...catch... 結(jié)構(gòu)分別捕獲客戶端和服務(wù)端的異常,并通過日志詳細(xì)記錄異常信息,以便于后續(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 從云端加載存儲(chǔ)的闖關(guān)進(jìn)度數(shù)據(jù)

在初始化 Init 方法中,實(shí)現(xiàn) CRUD-Save SDK 初始化后,繼續(xù)添加代碼,實(shí)現(xiàn)從云端加載存儲(chǔ)的闖關(guān)進(jìn)度數(shù)據(jù)。

  • 首先,調(diào)用 SDK 提供的 ListAllAsync 方法來獲取云端所有存檔文件。該方法需要傳入一個(gè) ListOptions 類型的參數(shù),其中可以指定存檔所屬的命名空間、角色I(xiàn)D、存檔模式、是否包含封面等選項(xiàng)。并將命名空間設(shè)置為之前定義的常量 SAVE_NS_STAGE_SCORES,以便只查詢與關(guān)卡進(jìn)度相關(guān)的存檔文件。

  • 判斷下如果返回的存檔文件列表(saveItems)不為空,說明云端已經(jīng)存在相關(guān)的存檔文件。此時(shí),代碼會(huì)獲取列表中第一條存檔的 SaveId,并將其保存到變量 _stageScoresSaveId 中。接著,調(diào)用之前封裝的 FetchPlayerProgress 方法,加載該存檔 ID 對(duì)應(yīng)的存檔數(shù)據(jù),并在闖關(guān)界面上進(jìn)行展示。

  • 如果返回的存檔文件列表為空,說明當(dāng)前沒有任何存檔信息。此時(shí)會(huì)輸出日志提示,并調(diào)用 StageManager.cs 腳本中的 LoadEmptyStageScore 方法,從第一關(guān)開始初始化游戲進(jì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}");         }     }     //...... } 

運(yùn)行游戲后進(jìn)行測(cè)試,看到闖關(guān)界面上的 UI 已經(jīng)實(shí)時(shí)更新了,說明成功加載到了云端存檔文件中的數(shù)據(jù)。

3.6 清空存檔數(shù)據(jù)

當(dāng)玩家退出登錄、切換賬號(hào)時(shí),如果該用戶沒有任何存檔數(shù)據(jù),需要清空當(dāng)前登錄用戶的存檔 ID 變量(_stageScoresSaveId),確保后續(xù)操作不會(huì)再關(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. 自動(dòng)云存檔功能(AutoSave)

除了通過 CRUD-Save SDK 提供的 CreateAsync 方法來手動(dòng)創(chuàng)建云存檔文件外,UOS 還提供了自動(dòng)云存檔功能(AutoSave)。

4.1 自動(dòng)云存檔的作用

自動(dòng)云存檔會(huì)在本地指定路徑定期保存存檔文件的同時(shí),自動(dòng)將該文件同步上傳到云端。這樣,用戶既能在本地快速訪問和恢復(fù)存檔,也能確保數(shù)據(jù)安全地備份在云端,防止因本地?cái)?shù)據(jù)丟失而造成損失。

自動(dòng)云存檔適合需要頻繁保存和同步進(jìn)度的場(chǎng)景,開發(fā)者只需簡(jiǎn)單配置(如文件名、保存間隔、沖突策略等),即可實(shí)現(xiàn)本地與云端的雙重存檔。

4.2 自動(dòng)云存檔的示例代碼參考

實(shí)現(xiàn)方式可以參考: CRUD-Save SDK 提供的示例腳本 AutoSaveSample.cs 中代碼的用法。

AutoSaveSample.cs 腳本演示了如何在 Unity 項(xiàng)目中集成 CRUD-Save 的自動(dòng)云存檔功能,實(shí)現(xiàn)本地文件定時(shí)的自動(dòng)上傳至云端。

  • 在初始化 CRUD-Save SDK 之后,可以先使用 UOS 提供的 Passport 登錄(即 Passport Login 方式),或者外部登錄的方式(ExternalLogin),來獲取用戶的認(rèn)證 Token。在當(dāng)前示例代碼中,我們暫時(shí)先以外部登錄的方式(ExternalLogin)來實(shí)現(xiàn)。

  • 然后調(diào)用 AutoSaveManager.cs 腳本封裝的EnableAutoSave 方法實(shí)現(xiàn)自動(dòng)云存檔,傳入 AutoSaveOptions 類型的配置(指定如文件名、自動(dòng)保存文件間隔、沖突策略、本地文件存儲(chǔ)路徑等),開啟自動(dòng)云存檔功能。此后,指定的本地文件會(huì)定期自動(dòng)同步到云端。

  • 協(xié)程方法 PerformFileOperations 是我們給出的一個(gè)本地文件的操作演示。


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,可傳入一對(duì)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為選填項(xiàng)
            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 運(yùn)行測(cè)試示例代碼

接著,我們可以測(cè)試下上面的腳本!大家先自行創(chuàng)建一個(gè)新的項(xiàng)目工程,綁定好創(chuàng)建的 UOS App,開通 CRUD-Save 服務(wù)并安裝 SDK。

然后在場(chǎng)景中創(chuàng)建一個(gè)空對(duì)象,可以暫時(shí)命名為 AutoSaveSample,將 AutoSaveSample.cs 腳本掛載給空對(duì)象,并為 Inspector 面板上的 userId 變量賦值,當(dāng)前先暫時(shí)設(shè)置為:externalLogin_userId。

然后運(yùn)行項(xiàng)目,在 Console 控制臺(tái)可以看到相關(guān)的日志信息:說明存檔文件自動(dòng)上傳成功了。

進(jìn)入「CRUD Save」「存檔管理」頁面,可以看到已經(jīng)自動(dòng)上傳的文件名為「autoSave」的存檔文件:

在腳本中設(shè)置的 Application.persistentDataPath 路徑下,可以看到同時(shí)也有一份存檔文件的。當(dāng)然,本地存檔的路徑,大家可以在腳本中自行設(shè)置的:

4.4 本地存檔和云存檔的沖突解決

當(dāng)本地存檔和云端存檔因文件更新時(shí)間不一致發(fā)生沖突時(shí),我們提供了以下三種沖突解決策略,大家可根據(jù)實(shí)際需求選擇適合的方式:

public enum ConflictStrategy
    {
        // 默認(rèn),沖突時(shí)報(bào)錯(cuò):"本地存檔和云存檔存在沖突,需要手動(dòng)解決。"
        Default = 0,
        // 拋棄本地存檔,保留云存檔
        DiscardLocal = 1,
        // 保留最后寫入存檔
        LastWrite = 3
    }

Default(默認(rèn))

  • 含義:當(dāng)本地存檔和云存檔更新時(shí)間不一致發(fā)生沖突時(shí),系統(tǒng)會(huì)報(bào)錯(cuò),提示“本地存檔和云存檔存在沖突,需要手動(dòng)解決”。

  • 適用場(chǎng)景:適合對(duì)存檔一致性要求很高的場(chǎng)景,需要開發(fā)者或用戶手動(dòng)選擇用哪個(gè)存檔,防止數(shù)據(jù)丟失或覆蓋。

DiscardLocal(拋棄本地存檔)

  • 含義:當(dāng)發(fā)生沖突時(shí),直接丟棄本地存檔,保留云端存檔的數(shù)據(jù)。

  • 適用場(chǎng)景:適合以云端數(shù)據(jù)為主的場(chǎng)景,比如多端同步,或者認(rèn)為云端數(shù)據(jù)更權(quán)威、更安全的情況。

LastWrite(保留最后寫入存檔)

  • 含義:無論是本地還是云端,誰最后寫入,誰的數(shù)據(jù)就被保留(即“最后寫入優(yōu)先”)。

  • 適用場(chǎng)景:適合需要自動(dòng)解決沖突、以最新操作為準(zhǔn)的場(chǎng)景,比如頻繁切換設(shè)備、多人協(xié)作但只需最新進(jìn)度的游戲。

下節(jié)教程預(yù)告

教程主題——《火拼24》系列教程四:微信小游戲CDN資源部署

在《火拼24》系列教程第四章中,我們將聚焦于微信小游戲的 CDN 資源部署。教程將詳細(xì)介紹如何將游戲資源進(jìn)行打包,并上傳到 CDN 平臺(tái)。通過本篇內(nèi)容,你將掌握微信小游戲上線前資源部署的完整流程,為游戲的流暢運(yùn)行和優(yōu)質(zhì)體驗(yàn)提供有力保障。

小貼士:為方便大家提前學(xué)習(xí),教程第四章節(jié)的分支代碼已同步更新,可提前下載查閱或本地調(diào)試。

  • 教程四:初始項(xiàng)目工程(供學(xué)習(xí)參考)

https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson4-start

  • 教程四:完整示例工程參考(可直接運(yùn)行)

https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson4-end

記得鎖定更新,別錯(cuò)過每一步關(guān)鍵指南!

Unity Online Services (UOS) 是一個(gè)專為游戲開發(fā)者設(shè)計(jì)的一站式游戲云服務(wù)平臺(tái),提供覆蓋游戲全生命周期的開發(fā)、運(yùn)營(yíng)和推廣支持。

了解更多 UOS 相關(guān)信息:

官網(wǎng):https://uos.unity.cn

技術(shù)交流 QQ 群:823878269

Unity 官方微信

第一時(shí)間了解Unity引擎動(dòng)向,學(xué)習(xí)進(jìn)階開發(fā)技能


每一個(gè)“點(diǎn)贊”、“在看”,都是我們前進(jìn)的動(dòng)力

特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(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.

相關(guān)推薦
熱點(diǎn)推薦
近期皮膚癢別不當(dāng)回事,當(dāng)心是這種問題找上門!中老年人尤其注意

近期皮膚癢別不當(dāng)回事,當(dāng)心是這種問題找上門!中老年人尤其注意

科普中國(guó)
2025-10-28 21:35:48
谷正文91歲接受采訪,談到吳石時(shí),只輕描淡寫地說了兩句話

谷正文91歲接受采訪,談到吳石時(shí),只輕描淡寫地說了兩句話

大國(guó)紀(jì)錄
2025-10-24 15:47:09
日本半導(dǎo)體封鎖110家中企,涉及幾乎全部領(lǐng)域,制裁遠(yuǎn)比美國(guó)猛烈

日本半導(dǎo)體封鎖110家中企,涉及幾乎全部領(lǐng)域,制裁遠(yuǎn)比美國(guó)猛烈

小樾說歷史
2025-10-29 14:46:33
官宣,正式加盟,鄒雨宸做出決定,出發(fā)廣東,名單公布,薪酬曝光

官宣,正式加盟,鄒雨宸做出決定,出發(fā)廣東,名單公布,薪酬曝光

樂聊球
2025-10-29 09:43:49
高端電車自燃,有錢人都慌了?

高端電車自燃,有錢人都慌了?

智選車
2025-10-28 13:55:58
吸引力法則:多做高能量的事情,你的運(yùn)氣會(huì)好到離譜

吸引力法則:多做高能量的事情,你的運(yùn)氣會(huì)好到離譜

阿胖讀書
2025-10-29 15:10:26
維尼修斯國(guó)家德比后帶女友去度假,同行的還有米利唐夫婦

維尼修斯國(guó)家德比后帶女友去度假,同行的還有米利唐夫婦

懂球帝
2025-10-29 14:01:03
A股:剛剛,國(guó)務(wù)院國(guó)資委發(fā)起,一方向迎大利好,周四將有大動(dòng)作

A股:剛剛,國(guó)務(wù)院國(guó)資委發(fā)起,一方向迎大利好,周四將有大動(dòng)作

有范又有料
2025-10-29 20:32:11
貝克漢姆幼子30歲女友惹爭(zhēng)議,被找來當(dāng)助理,卻把孩子“變臟”了

貝克漢姆幼子30歲女友惹爭(zhēng)議,被找來當(dāng)助理,卻把孩子“變臟”了

譯言
2025-10-28 09:58:35
韓國(guó)乒壇丑聞!柳承敏涉嫌受賄2億遭警方調(diào)查,奧運(yùn)擊敗王皓奪冠

韓國(guó)乒壇丑聞!柳承敏涉嫌受賄2億遭警方調(diào)查,奧運(yùn)擊敗王皓奪冠

念洲
2025-10-29 10:40:20
N站最新《劍星》服裝mod:伊芙也太好看了

N站最新《劍星》服裝mod:伊芙也太好看了

游民星空
2025-10-29 15:05:17
特朗普欲降低關(guān)稅換取中方遏制芬太尼出口,外交部:美方應(yīng)為合作創(chuàng)造必要條件

特朗普欲降低關(guān)稅換取中方遏制芬太尼出口,外交部:美方應(yīng)為合作創(chuàng)造必要條件

澎湃新聞
2025-10-29 15:32:31
日本球迷已經(jīng)對(duì)張本智和沒有信心了!

日本球迷已經(jīng)對(duì)張本智和沒有信心了!

十點(diǎn)街球體育
2025-10-29 16:40:06
上海女博士在家8年未出門,警察破門后,屋內(nèi)景象讓人傻眼

上海女博士在家8年未出門,警察破門后,屋內(nèi)景象讓人傻眼

蘭姐說故事
2025-04-28 10:00:09
青島市紀(jì)委監(jiān)委最新通報(bào),吳紹元被查

青島市紀(jì)委監(jiān)委最新通報(bào),吳紹元被查

齊魯壹點(diǎn)
2025-10-29 19:32:09
"只談笑風(fēng)生,但不可以動(dòng)情":成年人的心動(dòng),注定輸

"只談笑風(fēng)生,但不可以動(dòng)情":成年人的心動(dòng),注定輸

青蘋果sht
2025-10-27 10:03:03
突傳死訊!香港知名演員第四任妻子離世,前一天晚上剛打完流感針

突傳死訊!香港知名演員第四任妻子離世,前一天晚上剛打完流感針

東方不敗然多多
2025-10-29 02:01:23
老年人行房最晚到多大年齡?或許很多人想錯(cuò)了!

老年人行房最晚到多大年齡?或許很多人想錯(cuò)了!

深度報(bào)
2025-09-11 23:05:16
社保斷繳、未繳滿15年或20年,2025年新規(guī)下,全都這樣處理!

社保斷繳、未繳滿15年或20年,2025年新規(guī)下,全都這樣處理!

新浪財(cái)經(jīng)
2025-09-04 16:11:44
Meta美股盤后跌超5%

Meta美股盤后跌超5%

財(cái)聯(lián)社
2025-10-30 04:08:11
2025-10-30 05:35:00
Unity incentive-icons
Unity
Unity中國(guó)官方帳戶
2385文章數(shù) 6728關(guān)注度
往期回顧 全部

游戲要聞

三國(guó)望神州:全新限定張飛抽取價(jià)值分析!三爺是不會(huì)讓我們失望的

頭條要聞

日媒:“高市早苗當(dāng)面拒絕美國(guó)”

頭條要聞

日媒:“高市早苗當(dāng)面拒絕美國(guó)”

體育要聞

Here we go!羅馬諾:斯帕萊蒂即將出任尤文主帥

娛樂要聞

她二婚嫁給許紹雄,恩愛40年不離不棄

財(cái)經(jīng)要聞

美聯(lián)儲(chǔ)降息25個(gè)基點(diǎn) 12月起結(jié)束縮表

科技要聞

英偉達(dá)GTC:黃仁勛撒錢、造芯、造夢(mèng)

汽車要聞

自信大廠做派 全新瑞虎8詮釋什么是穩(wěn)中進(jìn)化

態(tài)度原創(chuàng)

手機(jī)
本地
藝術(shù)
親子
家居

手機(jī)要聞

榮耀10000mAh電池完成備案:X80系列、Power2,準(zhǔn)備刷新續(xù)航記錄

本地新聞

全網(wǎng)圍觀,到底多少人被這個(gè)野人大學(xué)生笑瘋了

藝術(shù)要聞

她的美,竟讓全球人像雜志爭(zhēng)相刊登!

親子要聞

霖霖哥很專業(yè),比我還會(huì)逗銳銳弟笑

家居要聞

純白質(zhì)感 簡(jiǎn)約而不簡(jiǎn)單

無障礙瀏覽 進(jìn)入關(guān)懷版 亚洲一区二区图片| 无码囯产精品一区二区免费| 久久一本本道| 老熟妇露脸嗷嗷叫91九色| 精品无人乱码一区二区三区| 婷婷五月酒色丁香花开网| a观看v视频网站入口免费| 亚洲成亚洲成网| 韩国三级大全久久网站| 精品人妻区二区三区蜜桃| 最新亚洲人成无码www| 久久久久久国产精品免费免费四川| 亚洲日本一本dvd高清| 中文人妻熟妇乱又伦精品视频| 午夜激情影院欧美| 爱爱一二专区| 男人撕开奶罩揉吮奶头| 亚洲精品国产精品国产| 精品人妻无码| 日韩在线一区二区每天更新 | 天美av无码网站| 日韩欧美不卡一卡二卡3卡四卡2021免费| 性色A亚洲一区二区三区69天堂视频| 欧洲中文字幕一区二区| 动漫3D精品一区二区三区乱码| 亚洲国产精品久久久久婷蜜芽| 国产一区二区三区在线观看影院| 欧美精品一区二区性色a+v| 国产成人精品无码a区在线观看| 日韩欧美在线综合网| 亚洲成aⅴ人片| 欧美女人久久久| 国产亚洲第一色欲| 亚洲av日韩av无码污污网站 | 久久久久亚洲AV成人网毛片| 一本一本久久a久久综合精品蜜桃| 亚洲国产精品一区二区第四页 | 久久AV资源站| 天堂资源中文最新版在线一区| 大荫蒂一区二区三区| 成人区人妻精品一熟女|