本指南說明如何在 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_SNAPSHOT
為 true
,且 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()
方法以修訂已儲存的遊戲變更。
以下範例顯示如何建立變更及提交已儲存的遊戲。
首先,請開啟我們想要編輯的快照,並確認選擇所有基礎已解決所有衝突。
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 } });
接著,建立已儲存的遊戲變更,其中包含封面圖片使用的圖片資料:
gpg::SnapshotMetadataChange::Builder builder; gpg::SnapshotMetadataChange metadata_change = builder.SetDescription("CollectAllTheStar savedata") .SetCoverImageFromPngData(pngData).Create();
最後,修訂已儲存的遊戲變更。
gpg::SnapshotManager::CommitResponse commitResponse = service_->Snapshots().CommitBlocking(metadata, metadata_change, SetupSnapshotData());
資料參數會包含您儲存的所有儲存遊戲資料。 這項變更還包含其他已儲存的遊戲中繼資料,例如遊戲時間與已儲存遊戲的說明。
如果修訂作業順利完成,玩家可以在已儲存的遊戲選擇使用者介面中看到遊戲進度存檔。