保存済みゲームをゲームに追加する

Google ログイン API の非推奨に伴い、2026 年に Google Play Games サービス v1 の SDK を削除します。2025 年 2 月以降、Google Play Games サービス v1 の SDK と新たに統合されたタイトルを Google Play で公開することはできなくなります。代わりに Google Play Games サービス v2 の SDK を使用することをおすすめします。
以前のゲーム v1 統合を使用している既存のタイトルは、今後数年間は引き続き機能しますが、2025 年 6 月から v2 への移行を開始することをおすすめします。
このガイドは、Play Games サービス v1 SDK の使用を対象としています。Play ゲームサービス v2 の C++ SDK はまだ提供されていません。

このガイドでは、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);
}

次の例は、デフォルトの保存済みゲーム 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 保存済みゲーム サービスが解決アクションを実行しないことを示します。代わりに、ゲームはカスタム マージを実行します。
SnapshotConflictPolicy::LONGEST_PLAYTIME 保存済みゲーム サービスがプレイ時間の値が最も大きい保存済みゲームを選択する必要があることを示します。
SnapshotConflictPolicy::BASE_WINS 保存済みゲーム サービスがベースの保存済みゲームを選択する必要があることを示します。
SnapshotConflictPolicy::REMOTE_WINS 保存済みゲーム サービスがリモートの保存済みゲームを選択する必要があることを示します。リモート バージョンは、プレーヤーのデバイスのいずれかで検出され、ベース バージョンよりも新しいタイムスタンプを持つ保存済みゲームのバージョンです。

GPGSnapshotConflictPolicyManual 以外の競合ポリシーを指定した場合、保存済みゲーム サービスは保存済みゲームを統合し、結果の SnapshotManager::OpenResponse 値を介して更新されたバージョンを返します。ゲームは、保存済みゲームを開いて書き込み、SnapshotManager::Commit(...) メソッドを呼び出して保存済みゲームを Google のサーバーに commit できます。

カスタム結合を実行する

競合ポリシーとして 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() メソッドを呼び出して保存済みゲームの変更を commit します。

次の例は、変更を作成して保存済みゲームを 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 パラメータには、保存するゲームデータがすべて含まれます。この変更には、プレイ時間や保存済みゲームの説明など、保存済みゲームの追加のメタデータも含まれます。

コミット オペレーションが正常に完了すると、保存済みゲーム選択 UI に保存済みゲームが表示されます。