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

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

事前準備

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

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

資料格式和跨平台相容性

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

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

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

您必須先啟用遊戲進度存檔服務的存取權,才能使用這項服務。如要這樣做,請在使用 gpg::GameServices::Builder 建立服務時呼叫 EnableSnapshots()。這樣一來,系統就會在下次驗證事件中啟用 Saved Games 所需的額外驗證範圍。

顯示遊戲進度存檔

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

  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);
}

以下範例說明如何顯示預設的「Saved Games」UI,以及處理玩家的 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 會為玩家提供按鈕,讓他們建立新的儲存遊戲,而不是選取現有遊戲。(顯示時,按鈕位於 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 表示 Saved Games 服務不應執行任何解析動作。而是執行自訂合併
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());
    

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

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