เกมที่บันทึกไว้สำหรับเกม Android

คู่มือนี้จะแสดงวิธีใช้เกมที่บันทึกไว้โดยใช้ Snapshot API จากบริการเกมของ Google Play API จะอยู่ใน com.google.android.gms.games.snapshot และ com.google.android.gms.games แพ็กเกจของคุณ

ก่อนเริ่มต้น

สำหรับข้อมูลเกี่ยวกับฟีเจอร์นี้ โปรดดู ภาพรวมของเกมที่บันทึกไว้

รับไคลเอ็นต์สแนปชอต

ในการเริ่มใช้ Snapshot API เกมของคุณจะต้องรับ SnapshotsClient โดยการเรียกใช้ Games.getSnapshotsClient() และการส่งใน กิจกรรม

ระบุขอบเขตไดรฟ์

Snapshot API อาศัย Google Drive API เพื่อเก็บข้อมูลเกมที่บันทึกไว้ หากต้องการเข้าถึง Drive API แอปของคุณต้องระบุ Drive.SCOPE_APPFOLDER เมื่อสร้างไคลเอ็นต์ Google Sign-In

ตัวอย่างวิธีดำเนินการใน onResume() สำหรับกิจกรรมการลงชื่อเข้าใช้


@Override
protected void onResume() {
  super.onResume();
  signInSilently();
}

private void signInSilently() {
  GoogleSignInOptions signInOption =
      new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
          // Add the APPFOLDER scope for Snapshot support.
          .requestScopes(Drive.SCOPE_APPFOLDER)
          .build();

  GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption);
  signInClient.silentSignIn().addOnCompleteListener(this,
      new OnCompleteListener<GoogleSignInAccount>() {
        @Override
        public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
          if (task.isSuccessful()) {
            onConnected(task.getResult());
          } else {
            // Player will need to sign-in explicitly using via UI
          }
        }
      });
}

แสดงเกมที่บันทึกไว้

คุณสามารถผสานรวม Snapshot API ได้ทุกที่ที่เกมของคุณมอบให้ผู้เล่น ตัวเลือกในการบันทึกหรือคืนค่าความคืบหน้า เกมของคุณอาจแสดง ที่จุดบันทึก/กู้คืนที่กำหนดไว้ หรือให้ผู้เล่นบันทึกหรือคืนค่าได้ ความคืบหน้าได้ตลอดเวลา

เมื่อผู้เล่นเลือกตัวเลือกบันทึก/คืนค่าในเกมแล้ว เกมของคุณสามารถ เลือกเปิดหน้าจอที่แจ้งให้ผู้เล่นป้อนข้อมูล หรือเลือกเกมที่บันทึกไว้ที่มีอยู่แล้วเพื่อคืนค่า

Snapshot API จะระบุผู้ใช้สำหรับเลือกเกมที่บันทึกไว้ตามค่าเริ่มต้นเพื่อให้การพัฒนาของคุณง่ายขึ้น อินเทอร์เฟซ (UI) แบบพร้อมใช้งานได้ทันที UI การเลือกเกมที่บันทึกไว้ช่วยให้ผู้เล่น สร้างเกมใหม่ที่บันทึกไว้ ดูรายละเอียดเกี่ยวกับเกมที่บันทึกไว้ที่มีอยู่ และโหลดเกมที่บันทึกไว้ก่อนหน้านี้

หากต้องการเปิดใช้งาน UI เริ่มต้นของ "เกมที่บันทึกไว้" ให้ทำดังนี้

  1. โทรติดต่อ SnapshotsClient.getSelectSnapshotIntent() เพื่อรับ Intent สำหรับการเปิด UI การเลือกเกมที่บันทึกไว้ตามค่าเริ่มต้น
  2. โทร startActivityForResult() แล้วให้ผ่าน Intent หากการเรียกใช้สำเร็จ เกมจะแสดง UI การเลือกเกมที่บันทึกไว้พร้อมกับ ตามตัวเลือกที่คุณระบุไว้

ตัวอย่างวิธีเปิด UI การเลือกเกมที่บันทึกไว้ตามค่าเริ่มต้นมีดังนี้

private static final int RC_SAVED_GAMES = 9009;

private void showSavedGamesUI() {
  SnapshotsClient snapshotsClient =
      PlayGames.getSnapshotsClient(this);
  int maxNumberOfSavedGamesToShow = 5;

  Task<Intent> intentTask = snapshotsClient.getSelectSnapshotIntent(
      "See My Saves", true, true, maxNumberOfSavedGamesToShow);

  intentTask.addOnSuccessListener(new OnSuccessListener<Intent>() {
    @Override
    public void onSuccess(Intent intent) {
      startActivityForResult(intent, RC_SAVED_GAMES);
    }
  });
}

หากผู้เล่นเลือกที่จะสร้างเกมใหม่ที่บันทึกไว้หรือโหลดเกมที่บันทึกไว้ที่มีอยู่ UI จะส่งคำขอไปยังบริการเกมของ Play หากคำขอประสบความสำเร็จ บริการเกมของ Play จะแสดงข้อมูลสำหรับสร้างหรือกู้คืนเกมที่บันทึกไว้ผ่าน onActivityResult() Callback เกมของคุณจะลบล้าง Callback นี้เพื่อตรวจสอบว่าเกิดข้อผิดพลาดระหว่างคำขอหรือไม่

ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างการใช้งาน onActivityResult():

private String mCurrentSaveName = "snapshotTemp";

/**
 * This callback will be triggered after you call startActivityForResult from the
 * showSavedGamesUI method.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode,
                                Intent intent) {
  if (intent != null) {
    if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA)) {
      // Load a snapshot.
      SnapshotMetadata snapshotMetadata =
          intent.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA);
      mCurrentSaveName = snapshotMetadata.getUniqueName();

      // Load the game data from the Snapshot
      // ...
    } else if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_NEW)) {
      // Create a new snapshot named with a unique string
      String unique = new BigInteger(281, new Random()).toString(13);
      mCurrentSaveName = "snapshotTemp-" + unique;

      // Create the new snapshot
      // ...
    }
  }
}

เขียนเกมที่บันทึกไว้

วิธีจัดเก็บเนื้อหาไปยังเกมที่บันทึกไว้

  1. เปิดสแนปชอตแบบไม่พร้อมกันผ่าน SnapshotsClient.open()

  2. เรียกข้อมูล Snapshot จากผลลัพธ์ของงานด้วยการเรียกใช้ SnapshotsClient.DataOrConflict.getData()

  3. ดึงข้อมูล SnapshotContents อินสแตนซ์ที่มี SnapshotsClient.SnapshotConflict

  4. โทร SnapshotContents.writeBytes() เพื่อจัดเก็บข้อมูลโปรแกรมเล่นในรูปแบบไบต์

  5. เมื่อเขียนการเปลี่ยนแปลงทั้งหมดแล้ว ให้เรียก SnapshotsClient.commitAndClose() เพื่อส่งการเปลี่ยนแปลงของคุณไปยังเซิร์ฟเวอร์ของ Google ในการเรียกเมธอด เกมสามารถ (ไม่บังคับ) ให้ข้อมูลเพิ่มเติมเพื่อบอกให้บริการเกมของ Play ทราบวิธีทำ นำเสนอเกมที่บันทึกไว้นี้แก่ผู้เล่น ข้อมูลนี้จะแสดงใน SnapshotMetaDataChange ที่เกมของคุณสร้างขึ้นโดยใช้ SnapshotMetadataChange.Builder

ตัวอย่างต่อไปนี้แสดงวิธีที่เกมของคุณอาจทำการเปลี่ยนแปลงกับเกมที่บันทึกไว้

private Task<SnapshotMetadata> writeSnapshot(Snapshot snapshot,
                                             byte[] data, Bitmap coverImage, String desc) {

  // Set the data payload for the snapshot
  snapshot.getSnapshotContents().writeBytes(data);

  // Create the change operation
  SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder()
      .setCoverImage(coverImage)
      .setDescription(desc)
      .build();

  SnapshotsClient snapshotsClient =
      PlayGames.getSnapshotsClient(this);

  // Commit the operation
  return snapshotsClient.commitAndClose(snapshot, metadataChange);
}

หากอุปกรณ์ของโปรแกรมเล่นไม่ได้เชื่อมต่อกับเครือข่ายเมื่อแอปเรียกใช้ SnapshotsClient.commitAndClose() บริการเกมของ Play จะจัดเก็บข้อมูลเกมที่บันทึกไว้ไว้ในอุปกรณ์ บนอุปกรณ์ เชื่อมต่ออีกครั้ง บริการเกมของ Play จะซิงค์การเปลี่ยนแปลงเกมที่บันทึกไว้ในเครื่องที่แคชกับ เซิร์ฟเวอร์ของ Google

โหลดเกมที่บันทึกไว้

หากต้องการเรียกดูเกมที่บันทึกไว้สำหรับโปรแกรมเล่นที่ลงชื่อเข้าใช้ในปัจจุบัน ให้ทำดังนี้

  1. เปิดสแนปชอตด้วย SnapshotsClient.open()

  2. เอร็ดอร่อย Snapshot จากผลลัพธ์ของงานด้วยการเรียกใช้ SnapshotsClient.DataOrConflict.getData() อีกวิธีหนึ่งคือ เกมของคุณยังสามารถเรียกดู ผ่าน UI การเลือกเกมที่บันทึกไว้ ตามที่อธิบายไว้ใน การแสดงเกมที่บันทึกไว้

  3. เรียกข้อมูล SnapshotContents อินสแตนซ์ที่มี SnapshotsClient.SnapshotConflict

  4. โทร SnapshotContents.readFully() เพื่ออ่านเนื้อหาของสแนปชอต

ตัวอย่างต่อไปนี้แสดงวิธีโหลดเกมบางเกมที่บันทึกไว้

Task<byte[]> loadSnapshot() {
  // Display a progress dialog
  // ...

  // Get the SnapshotsClient from the signed in account.
  SnapshotsClient snapshotsClient =
      PlayGames.getSnapshotsClient(this);

  // In the case of a conflict, the most recently modified version of this snapshot will be used.
  int conflictResolutionPolicy = SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED;

  // Open the saved game using its name.
  return snapshotsClient.open(mCurrentSaveName, true, conflictResolutionPolicy)
      .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
          Log.e(TAG, "Error while opening Snapshot.", e);
        }
      }).continueWith(new Continuation<SnapshotsClient.DataOrConflict<Snapshot>, byte[]>() {
        @Override
        public byte[] then(@NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> task) throws Exception {
          Snapshot snapshot = task.getResult().getData();

          // Opening the snapshot was a success and any conflicts have been resolved.
          try {
            // Extract the raw data from the snapshot.
            return snapshot.getSnapshotContents().readFully();
          } catch (IOException e) {
            Log.e(TAG, "Error while reading Snapshot.", e);
          }

          return null;
        }
      }).addOnCompleteListener(new OnCompleteListener<byte[]>() {
        @Override
        public void onComplete(@NonNull Task<byte[]> task) {
          // Dismiss progress dialog and reflect the changes in the UI when complete.
          // ...
        }
      });
}

จัดการความขัดแย้งของเกมที่บันทึกไว้

เมื่อใช้ API สแนปชอตในเกม อาจมี เพื่ออ่านและเขียนในเกมเดียวกันที่บันทึกไว้ ในกรณีที่ อุปกรณ์ขาดการเชื่อมต่อเครือข่ายชั่วคราวและมีการเชื่อมต่ออีกครั้งในภายหลัง ก่อให้เกิดความขัดแย้งของข้อมูลซึ่งเกมที่บันทึกไว้ซึ่งจัดเก็บไว้ในอุปกรณ์ภายในของผู้เล่น ไม่ซิงค์กับเวอร์ชันระยะไกลที่จัดเก็บไว้ในเซิร์ฟเวอร์ของ Google

Snapshot API มีกลไกการแก้ไขข้อขัดแย้งที่แสดงทั้ง ชุดเกมที่บันทึกไว้ที่ขัดแย้งกันในเวลาที่อ่าน และช่วยให้คุณแก้ไขปัญหา กลยุทธ์ที่เหมาะกับเกมของคุณ

เมื่อบริการเกมของ Play ตรวจพบความขัดแย้งของข้อมูล SnapshotsClient.DataOrConflict.isConflict() จะแสดงผลค่า true ในเหตุการณ์นี้ SnapshotsClient.SnapshotConflict จะมีเกมที่บันทึกไว้ 2 เวอร์ชัน ได้แก่

  • เวอร์ชันของเซิร์ฟเวอร์: เวอร์ชันล่าสุดที่บริการเกมของ Play รู้จัก สำหรับอุปกรณ์ของผู้เล่น

  • เวอร์ชันในเครื่อง: เวอร์ชันที่แก้ไขแล้วซึ่งตรวจพบในอุปกรณ์ใดอุปกรณ์หนึ่งของโปรแกรมเล่น ที่มีเนื้อหาหรือข้อมูลเมตาที่ขัดแย้งกัน ซึ่งอาจไม่เหมือนกับ เวอร์ชันที่คุณพยายามบันทึก

เกมของคุณต้องตัดสินใจว่าจะแก้ไขความขัดแย้งอย่างไรด้วยการเลือกหนึ่งใน เวอร์ชันที่มีให้ หรือรวมข้อมูลของเกมเวอร์ชันที่บันทึกไว้ 2 เวอร์ชัน

วิธีตรวจหาและแก้ไขความขัดแย้งของเกมที่บันทึกไว้

  1. โทร SnapshotsClient.open() ผลลัพธ์ของงานมีคลาส SnapshotsClient.DataOrConflict

  2. เรียกใช้ SnapshotsClient.DataOrConflict.isConflict() หากผลลัพธ์เป็น "จริง" แสดงว่าคุณมีข้อขัดแย้งที่ต้องแก้ไข

  3. โทร SnapshotsClient.DataOrConflict.getConflict() เพื่อดึงข้อมูล SnaphotsClient.snapshotConflict อินสแตนซ์

  4. โทร SnapshotsClient.SnapshotConflict.getConflictId() เพื่อดึงข้อมูลรหัสความขัดแย้งที่ระบุความขัดแย้งที่ตรวจพบโดยเฉพาะ บัญชี เกมต้องใช้ค่านี้เพื่อส่งคำขอแก้ไขข้อขัดแย้งในภายหลัง

  5. โทร SnapshotsClient.SnapshotConflict.getConflictingSnapshot() เพื่อรับเวอร์ชันในเครื่อง

  6. โทร SnapshotsClient.SnapshotConflict.getSnapshot() เพื่อดูเวอร์ชันของเซิร์ฟเวอร์

  7. หากต้องการแก้ไขความขัดแย้งของเกมที่บันทึกไว้ ให้เลือกเวอร์ชันที่ต้องการบันทึกลงไป เซิร์ฟเวอร์เป็นเวอร์ชันล่าสุด และส่งไปยัง SnapshotsClient.resolveConflict()

ตัวอย่างต่อไปนี้แสดงและตัวอย่างวิธีที่เกมของคุณอาจจัดการกับความขัดแย้งของเกมที่บันทึกไว้โดย การเลือกเกมที่บันทึกไว้ที่ได้รับการแก้ไขล่าสุดเป็นเวอร์ชันสุดท้ายที่จะบันทึก:


private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10;

Task<Snapshot> processSnapshotOpenResult(SnapshotsClient.DataOrConflict<Snapshot> result,
                                         final int retryCount) {

  if (!result.isConflict()) {
    // There was no conflict, so return the result of the source.
    TaskCompletionSource<Snapshot> source = new TaskCompletionSource<>();
    source.setResult(result.getData());
    return source.getTask();
  }

  // There was a conflict.  Try resolving it by selecting the newest of the conflicting snapshots.
  // This is the same as using RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED as a conflict resolution
  // policy, but we are implementing it as an example of a manual resolution.
  // One option is to present a UI to the user to choose which snapshot to resolve.
  SnapshotsClient.SnapshotConflict conflict = result.getConflict();

  Snapshot snapshot = conflict.getSnapshot();
  Snapshot conflictSnapshot = conflict.getConflictingSnapshot();

  // Resolve between conflicts by selecting the newest of the conflicting snapshots.
  Snapshot resolvedSnapshot = snapshot;

  if (snapshot.getMetadata().getLastModifiedTimestamp() <
      conflictSnapshot.getMetadata().getLastModifiedTimestamp()) {
    resolvedSnapshot = conflictSnapshot;
  }

  return PlayGames.getSnapshotsClient(theActivity)
      .resolveConflict(conflict.getConflictId(), resolvedSnapshot)
      .continueWithTask(
          new Continuation<
              SnapshotsClient.DataOrConflict<Snapshot>,
              Task<Snapshot>>() {
            @Override
            public Task<Snapshot> then(
                @NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> task)
                throws Exception {
              // Resolving the conflict may cause another conflict,
              // so recurse and try another resolution.
              if (retryCount < MAX_SNAPSHOT_RESOLVE_RETRIES) {
                return processSnapshotOpenResult(task.getResult(), retryCount + 1);
              } else {
                throw new Exception("Could not resolve snapshot conflicts");
              }
            }
          });
}

แก้ไขเกมที่บันทึกไว้

ถ้าคุณต้องการรวมข้อมูลจากเกมที่บันทึกไว้หลายเกม หรือแก้ไขเกมที่มีอยู่ Snapshot เพื่อบันทึกไปยังเซิร์ฟเวอร์เป็นเวอร์ชันสุดท้ายที่แก้ไขแล้ว ให้ทำตามขั้นตอนต่อไปนี้ ขั้นตอน:

  1. โทร SnapshotsClient.open()

  2. โทร SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent() เพื่อรับ ออบเจ็กต์ SnapshotContents

  3. รวมข้อมูลจาก SnapshotsClient.SnapshotConflict.getConflictingSnapshot() และ SnapshotsClient.SnapshotConflict.getSnapshot() เข้าสู่ SnapshotContents จากขั้นตอนก่อนหน้า

  4. (ไม่บังคับ) สร้าง SnapshotMetadataChange เช่น มีการเปลี่ยนแปลงในช่องข้อมูลเมตา

  5. โทร SnapshotsClient.resolveConflict() ในการเรียกใช้เมธอดของคุณ ให้บัตร SnapshotsClient.SnapshotConflict.getConflictId() เป็นอาร์กิวเมนต์แรก และ SnapshotMetadataChange และ SnapshotContents ออบเจ็กต์ที่คุณแก้ไขก่อนหน้านี้เป็นรายการที่ 2 และ อาร์กิวเมนต์ที่ 3 ตามลำดับ

  6. หาก SnapshotsClient.resolveConflict() เรียกสำเร็จแล้ว API จะจัดเก็บออบเจ็กต์ Snapshot ไปยังเซิร์ฟเวอร์และ พยายามเปิดออบเจ็กต์ Snapshot ในอุปกรณ์ของคุณเอง

    • หากมีข้อขัดแย้ง SnapshotsClient.DataOrConflict.isConflict() จะแสดงผล true ด้วยวิธีนี้ เกมของคุณควรกลับไปยังขั้นตอนที่ 2 และทำตามขั้นตอนซ้ำเพื่อแก้ไขภาพรวมจนกว่า ความขัดแย้งจะได้รับการแก้ไข
    • หากไม่มีข้อขัดแย้ง SnapshotsClient.DataOrConflict.isConflict() แสดงผล false และออบเจ็กต์ Snapshot เปิดอยู่เพื่อให้เกมแก้ไข