將遊戲進度存檔加入遊戲中

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

事前準備

如果您尚未執行,請參閱遊戲進度存檔概念

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

資料格式和跨平台相容性

您儲存在 Google 伺服器上的「遊戲資料」必須採用 std::vector<uint8_t> 格式。「已儲存的遊戲」服務會妥善處理您的資料,以提供跨平台相容性;Android 應用程式可以在相同位元組資料中讀取資料,而且完全不需要跨平台相容性問題。

選擇已儲存的遊戲資料時,請避免使用平台專屬格式。強烈建議您使用 XML 或 JSON 等資料格式,並在多個平台上提供強而有力的資料庫支援。

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

您必須先啟用服務的存取權,才能使用「遊戲進度存檔」服務。方法是使用 EnableSnapshots() 建立服務時呼叫 gpg::GameServices::Builder。這樣即可啟用已儲存遊戲在下次驗證事件時所需的其他驗證範圍。

顯示遊戲進度存檔

在遊戲中,您可以提供選項,讓玩家觸發儲存或還原已儲存的遊戲。玩家選取這個選項後,遊戲應顯示一個顯示現有儲存運算單元的畫面,並允許玩家從這些運算單元儲存或載入,或者建立新的儲存遊戲。請使用下列方法:

  SnapshotManager::ShowSelectUIOperation(...)

遊戲進度存檔使用者介面可讓玩家建立新的已儲存的遊戲、查看現有遊戲的儲存狀況,並載入之前儲存的遊戲。

  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 選項:

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

如上例所示,ALLOW_CREATE_SNAPSHOTtrue,且 MAX_SNAPSHOTS 大於使用者目前建立的實際快照數量,預設的快照 UI 可讓玩家使用新的儲存遊戲,而非選取現有的儲存遊戲。(顯示按鈕時,按鈕位於使用者介面的底部)。當玩家點選這個按鈕時,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 表示 Saved Games 服務應選擇遠端儲存的遊戲。遠端版本是指在其中一個玩家裝置上偵測到已儲存遊戲的版本,其時間戳記比基本版本更晚。

如果指定 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());
    

    資料參數會包含您儲存的所有儲存遊戲資料。 這項變更還包含其他已儲存的遊戲中繼資料,例如遊戲時間與已儲存遊戲的說明。

如果修訂作業順利完成,玩家可以在已儲存的遊戲選擇使用者介面中看到遊戲進度存檔。