在遊戲中新增遊戲進度存檔

Google 登入 API 淘汰後,我們將於 2026 年移除遊戲服務第 1 版 SDK。2025 年 2 月後,新整合遊戲服務第 1 版 SDK 的遊戲將無法在 Google Play 發布,建議改用遊戲服務第 2 版 SDK。
雖然整合舊版遊戲第 1 版的現有遊戲仍可運作幾年,但我們建議您自 2025 年 6 月起遷移至第 2 版
本指南適用於 Play 遊戲服務第 1 版 SDK。Play 遊戲服務第 2 版的 C++ SDK 尚未推出。

本指南說明如何在 C++ 應用程式中使用遊戲進度存檔服務,儲存及載入玩家的遊戲進度資料。您可以使用這項服務,在遊戲過程中隨時自動載入及儲存玩家的遊戲進度。這項服務也能讓玩家觸發使用者介面,更新或還原現有的儲存遊戲,或是建立新的儲存遊戲。

事前準備

建議您先複習已儲存的遊戲遊戲概念,這會對您很有幫助。

開始使用 Saved Games API 編寫程式碼之前:

資料格式和跨平台相容性

儲存至 Google 伺服器的遊戲進度存檔資料必須採用 std::vector<uint8_t> 格式。遊戲進度存檔服務會負責編碼資料,確保跨平台相容性;Android 應用程式可以將這項資料讀取為位元組陣列,不會有任何跨平台相容性問題。

為遊戲進度存檔資料選擇資料格式時,請避免使用平台專屬格式。強烈建議您使用 XML 或 JSON 等資料格式,這類格式在多個平台都有強大的程式庫支援。

啟用「遊戲進度存檔」服務

您必須先啟用存取權,才能使用遊戲進度存檔服務。如要這麼做,請使用 gpg::GameServices::Builder 建立服務時呼叫 EnableSnapshots()。這會在下次授權事件中,啟用「已儲存的遊戲」所需的額外授權範圍。

顯示遊戲進度存檔

您可以在遊戲中提供選項,讓玩家觸發儲存或還原遊戲進度存檔。玩家選取這個選項後,遊戲應會顯示現有的儲存空間,並允許玩家儲存至或載入其中一個空間,或建立新的遊戲進度存檔。請使用下列方法:

  SnapshotManager::ShowSelectUIOperation(...)

遊戲進度存檔選項 UI 可讓玩家建立新的遊戲進度存檔、查看現有遊戲進度存檔,以及載入先前儲存的遊戲進度存檔。

  SnapshotManager::SnapshotSelectUIResponse response;
  if (IsSuccess(response.status)) {
  if (response.data.Valid()) {
    LogI("Description: %s", response.data.Description().c_str());
    LogI("FileName %s", response.data.FileName().c_str());
    //Opening the snapshot data
    
  } else {
    LogI("Creating new snapshot");
    
  }
} else {
  LogI("ShowSelectUIOperation returns an error %d", response.status);
}

以下範例說明如何顯示預設的遊戲進度存檔 UI,以及處理玩家的 UI 選項:

  service_->Snapshots().ShowSelectUIOperation(
  ALLOW_CREATE_SNAPSHOT,
  ALLOW_DELETE_SNAPSHOT,
  MAX_SNAPSHOTS,
  SNAPSHOT_UI_TITLE,
  [this](gpg::SnapshotManager::SnapshotSelectUIResponse const & response) {
  
      }

如果以上述範例中的 ALLOW_CREATE_SNAPSHOT 大於使用者目前建立的實際快照數量,預設快照 UI 會為玩家提供建立新儲存遊戲的按鈕,而非選取現有遊戲。MAX_SNAPSHOTStrue(如果顯示按鈕,會位於使用者介面底部)。如果玩家點選這個按鈕,SnapshotSelectUIResponse 回應會有效,但沒有資料。

開啟及讀取遊戲進度存檔

如要存取遊戲進度存檔並讀取或修改內容,請先開啟代表該存檔的 SnapshotMetadata 物件。接著,呼叫 SnapshotManager::Read*() 方法。

以下範例說明如何開啟遊戲進度存檔:

  LogI("Opening file");
  service_->Snapshots()
  .Open(current_snapshot_.FileName(),
               gpg::SnapshotConflictPolicy::BASE_WINS,
        [this](gpg::SnapshotManager::OpenResponse const & response) {
           LogI("Reading file");
           gpg::SnapshotManager::ReadResponse responseRead =
           service_->Snapshots().ReadBlocking(response.data);
          
        }

偵測並解決資料衝突

開啟 SnapshotMetadata 物件時,遊戲進度存檔服務會偵測是否有衝突的遊戲進度存檔。如果玩家在本機裝置中的遊戲進度存檔與 Google 伺服器中儲存的遠端版本不同步,就可能會發生資料衝突。

開啟遊戲進度存檔時指定的衝突政策,會告知遊戲進度存檔服務如何自動解決資料衝突。政策可以是下列其中一項:

衝突政策 說明
SnapshotConflictPolicy::MANUAL 指出「已儲存的遊戲」服務不應執行任何解決動作。遊戲會改為執行自訂合併
SnapshotConflictPolicy::LONGEST_PLAYTIME 表示遊戲進度存檔服務應挑選遊戲時間值最大的遊戲進度存檔。
SnapshotConflictPolicy::BASE_WINS 指出遊戲進度存檔服務應挑選基本遊戲進度存檔。
SnapshotConflictPolicy::REMOTE_WINS 表示「遊戲進度存檔」服務應選擇遠端儲存的遊戲。遠端版本是指在其中一部玩家裝置上偵測到的已儲存遊戲版本,且時間戳記比基本版本新。

如果您指定的衝突政策不是 GPGSnapshotConflictPolicyManual,遊戲進度存檔服務會合併遊戲進度存檔,並透過產生的 SnapshotManager::OpenResponse 值傳回更新版本。遊戲可以開啟遊戲進度存檔、寫入資料,然後呼叫 SnapshotManager::Commit(...) 方法,將遊戲進度存檔提交至 Google 伺服器。

執行自訂合併

如果您將 SnapshotConflictPolicy::MANUAL 指定為衝突政策,遊戲必須先解決偵測到的任何資料衝突,才能對遊戲進度執行進一步的讀取或寫入作業。

在這種情況下,服務偵測到資料衝突時,會透過 SnapshotManager::OpenResponse 傳回下列參數:

  • conflict_id,用於專屬識別這項衝突 (您會在提交最終版本的遊戲進度時使用這個值);
  • 有衝突的遊戲進度基本版本;以及
  • 發生衝突的遠端遊戲進度存檔版本。

遊戲必須決定要儲存哪些資料,然後呼叫 SnapshotManager::ResolveConflictBlocking() 方法,將最終版本提交/解決至 Google 伺服器。

    //Resolve conflict
    gpg::SnapshotManager::OpenResponse resolveResponse =
        manager.ResolveConflictBlocking(openResponse.conflict_base, metadata_change,
                                  openResponse.conflict_id);

寫入遊戲進度存檔

如要寫入遊戲進度,請先開啟代表該遊戲進度的 SnapshotMetadata 物件、解決偵測到的任何資料衝突,然後呼叫 SnapshotManager::Commit() 方法來提交遊戲進度變更。

以下範例說明如何建立變更並提交遊戲進度存檔。

  1. 首先,開啟要編輯的快照,並選擇基底解決所有衝突。

    service_->Snapshots().Open(
          file_name,
          gpg::SnapshotConflictPolicy::BASE_WINS,
          [this](gpg::SnapshotManager::OpenResponse const &response) {
            if (IsSuccess(response.status)) {
              // metadata : gpg::SnapshotMetadata
              metadata = response.data;
            } else {
              // Handle snapshot open error here
            }
          });
    
  2. 接著,建立遊戲進度存檔變更,其中包含用於封面圖片的圖片資料:

    gpg::SnapshotMetadataChange::Builder builder;
    gpg::SnapshotMetadataChange metadata_change =
        builder.SetDescription("CollectAllTheStar savedata")
                 .SetCoverImageFromPngData(pngData).Create();
    
  3. 最後,提交遊戲進度存檔變更。

    gpg::SnapshotManager::CommitResponse commitResponse =
        service_->Snapshots().CommitBlocking(metadata, metadata_change, SetupSnapshotData());
    

    資料參數包含您儲存的所有遊戲進度資料。 這項變更也包含其他遊戲進度存檔中繼資料,例如遊戲時間和遊戲進度存檔說明。

如果提交作業順利完成,玩家就能在遊戲進度存檔選擇 UI 中看到存檔。