คู่มือนี้จะแสดงวิธีใช้เกมเกมที่บันทึกไว้โดยใช้
Snapshot API จากบริการเกมของ Google Play API จะอยู่ใน
com.google.android.gms.games.snapshot
และแพ็กเกจ com.google.android.gms.games
แพ็กเกจ
ก่อนเริ่มต้น
ซึ่งหากคุณยังไม่ได้อ่าน อาจเป็นประโยชน์ในการตรวจสอบ แนวคิดเกมที่บันทึกไว้
- ตรวจสอบว่าได้เปิดใช้การรองรับเกมที่บันทึกไว้แล้ว สำหรับเกมของคุณใน Google Play Console แล้ว
- ดาวน์โหลดและตรวจสอบตัวอย่างโค้ดเกมที่บันทึกไว้ใน หน้าตัวอย่างสำหรับ Android
- ทําความคุ้นเคยกับคําแนะนําที่อธิบายไว้ใน รายการตรวจสอบคุณภาพ
การรับไคลเอ็นต์สแนปชอต
ในการเริ่มใช้ 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 OnCompleteListenerG<oogleSignInAccount(>) { @Override public void onComplete(@NonNull TaskG<oogleSignInAccount >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 เริ่มต้นของ "เกมที่บันทึกไว้" ให้ทำดังนี้
- โทรติดต่อ
SnapshotsClient.getSelectSnapshotIntent()
เพื่อรับIntent
สำหรับการเปิดใช้ค่าเริ่มต้น UI การเลือกเกมที่บันทึกไว้ - โทร
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 ส่งคำขอไปยังบริการเกมของ Google Play หากคำขอประสบความสำเร็จ
บริการเกมของ Google 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 // ... } } }
การเขียนเกมที่บันทึกไว้
วิธีจัดเก็บเนื้อหาไปยังเกมที่บันทึกไว้
- เปิดสแนปชอตผ่าน
SnapshotsClient.open()
แบบไม่พร้อมกัน จากนั้น เรียกออบเจ็กต์Snapshot
จากผลลัพธ์ของงานโดยเรียกใช้SnapshotsClient.DataOrConflict.getData()
- ดึงข้อมูลอินสแตนซ์
SnapshotContents
ผ่านSnapshotsClient.SnapshotConflict
- เรียกใช้
SnapshotContents.writeBytes()
เพื่อจัดเก็บข้อมูลโปรแกรมเล่นในรูปแบบไบต์ - เมื่อเขียนการเปลี่ยนแปลงทั้งหมดแล้ว ให้เรียก
SnapshotsClient.commitAndClose()
เพื่อส่งการเปลี่ยนแปลงไปยังเซิร์ฟเวอร์ของ Google ในการเรียกใช้เมธอด เกมของคุณเลือกที่จะให้ข้อมูลเพิ่มเติมเพื่อบอกบริการเกมของ 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()
บริการเกมของ Google Play จะจัดเก็บข้อมูลเกมที่บันทึกไว้ในเครื่อง
อุปกรณ์ เมื่อเชื่อมต่ออุปกรณ์อีกครั้ง บริการเกมของ Google Play จะซิงค์เกมที่บันทึกไว้ในเครื่องและจัดเก็บไว้ในเครื่อง
เปลี่ยนแปลงไปยังเซิร์ฟเวอร์ของ Google
กำลังโหลดเกมที่บันทึกไว้
หากต้องการเรียกดูเกมที่บันทึกไว้สำหรับโปรแกรมเล่นที่ลงชื่อเข้าใช้ในปัจจุบัน ให้ทำดังนี้
- เปิดสแนปชอตผ่าน
SnapshotsClient.open()
แบบไม่พร้อมกัน จากนั้น เรียกออบเจ็กต์Snapshot
จากผลลัพธ์ของงานโดยเรียกใช้SnapshotsClient.DataOrConflict.getData()
อีกวิธีหนึ่งคือ เกมยังสามารถเรียกภาพรวมที่เฉพาะเจาะจงผ่าน UI การเลือกเกมที่บันทึกไว้ ดังที่อธิบายไว้ใน การแสดงเกมที่บันทึกไว้ - ดึงข้อมูลอินสแตนซ์
SnapshotContents
ผ่านSnapshotsClient.SnapshotConflict
- เรียกใช้
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 มีกลไกการแก้ไขข้อขัดแย้งที่แสดงทั้ง ชุดเกมที่บันทึกไว้ที่ขัดแย้งกันในเวลาที่อ่าน และช่วยให้คุณแก้ไขปัญหา กลยุทธ์ที่เหมาะกับเกมของคุณ
เมื่อบริการเกมของ Google Play ตรวจพบความขัดแย้งของข้อมูล
เมธอด SnapshotsClient.DataOrConflict.isConflict()
จะแสดงผลค่า true
ในเหตุการณ์นี้
ชั้นเรียน SnapshotsClient.SnapshotConflict
มีเกมที่บันทึกไว้ 2 เวอร์ชัน ได้แก่
- เวอร์ชันของเซิร์ฟเวอร์: เวอร์ชันล่าสุดที่บริการเกมของ Google Play ทราบว่ามีความแม่นยำ สำหรับอุปกรณ์ของโปรแกรมเล่น และ
- เวอร์ชันในเครื่อง: เวอร์ชันที่แก้ไขแล้วซึ่งตรวจพบในอุปกรณ์ของโปรแกรมเล่นหนึ่งที่มี เนื้อหาหรือข้อมูลเมตาที่ขัดแย้งกัน ซึ่งอาจไม่ใช่เวอร์ชันที่คุณพยายามบันทึก
เกมของคุณต้องตัดสินใจว่าจะแก้ไขความขัดแย้งอย่างไรด้วยการเลือกหนึ่งใน เวอร์ชันที่มีให้ หรือรวมข้อมูลของเกมเวอร์ชันที่บันทึกไว้ 2 เวอร์ชัน
วิธีตรวจหาและแก้ไขความขัดแย้งของเกมที่บันทึกไว้
- โทร
SnapshotsClient.open()
ผลลัพธ์ของงานมีคลาสSnapshotsClient.DataOrConflict
- เรียกใช้เมธอด
SnapshotsClient.DataOrConflict.isConflict()
หากผลลัพธ์เป็น "จริง" คุณมี ความขัดแย้งที่ต้องแก้ไข - โทรหา
SnapshotsClient.DataOrConflict.getConflict()
เพื่อเรียกข้อมูลSnaphotsClient.snapshotConflict
อินสแตนซ์ - เรียกใช้
SnapshotsClient.SnapshotConflict.getConflictId()
เพื่อเรียกข้อมูลรหัสความขัดแย้งที่ไม่ซ้ำกัน ระบุความขัดแย้งที่ตรวจพบ เกมของคุณต้องใช้ค่านี้เพื่อส่งคำขอแก้ไขข้อขัดแย้ง ในภายหลัง - โทรติดต่อ
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
เพื่อขอรับเวอร์ชันในเครื่อง - เรียกใช้
SnapshotsClient.SnapshotConflict.getSnapshot()
เพื่อรับเวอร์ชันของเซิร์ฟเวอร์ - หากต้องการแก้ไขความขัดแย้งของเกมที่บันทึกไว้ ให้เลือกเวอร์ชันที่คุณต้องการบันทึกไปยังเซิร์ฟเวอร์เป็น
เวอร์ชันสุดท้าย และส่งไปยังเมธอด
SnapshotsClient.resolveConflict()
ตัวอย่างต่อไปนี้แสดงและตัวอย่างวิธีที่เกมของคุณอาจจัดการกับความขัดแย้งของเกมที่บันทึกไว้โดย การเลือกเกมที่บันทึกไว้ที่ได้รับการแก้ไขล่าสุดเป็นเวอร์ชันสุดท้ายที่จะบันทึก:
private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10; TaskS<napshot >processSnapshotOpenResult(SnapshotsClient.DataOrConflictS<napshot >result, final int retryCount) { if (!result.isConflict()) { // There was no conflict, so return the result of the source. TaskCompletionSourceS<napshot >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.DataOrConflictS<napshot,> TaskS<napshot(>>) { @Override public TaskS<napshot >then( @NonNull TaskS<napshotsClient.DataOrConflictS<napshot >>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(C"ould not resolve snapshot conflicts)"; } } }); }
การแก้ไขเกมที่บันทึกไว้เพื่อแก้ไขความขัดแย้ง
หากต้องการรวมข้อมูลจากเกมที่บันทึกไว้หลายเกมหรือแก้ไข Snapshot
ที่มีอยู่
หากต้องการบันทึกไปยังเซิร์ฟเวอร์เป็นเวอร์ชันสุดท้ายที่แก้ไขแล้ว ให้ทำตามขั้นตอนต่อไปนี้
- โทรหา
SnapshotsClient.open()
- โทรหา
SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
เพื่อรับ ออบเจ็กต์SnapshotContents
- รวมข้อมูลจาก
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
และSnapshotsClient.SnapshotConflict.getSnapshot()
ลงในออบเจ็กต์SnapshotContents
จาก ขั้นตอนก่อนหน้า - (ไม่บังคับ) สร้างอินสแตนซ์
SnapshotMetadataChange
หากมีการเปลี่ยนแปลงกับข้อมูลเมตา ด้วย - โทร
SnapshotsClient.resolveConflict()
ในการเรียกใช้เมธอด ให้ส่งในSnapshotsClient.SnapshotConflict.getConflictId()
เป็นอาร์กิวเมนต์แรก และSnapshotMetadataChange
และSnapshotContents
ออบเจ็กต์ที่คุณแก้ไขก่อนหน้านี้เป็นรายการที่ 2 และ อาร์กิวเมนต์ที่ 3 ตามลำดับ - หากการเรียก
SnapshotsClient.resolveConflict()
สำเร็จ API จะจัดเก็บSnapshot
ไปยังเซิร์ฟเวอร์และพยายามเปิดออบเจ็กต์ Snapshot ในอุปกรณ์ของคุณเอง- หากมีข้อขัดแย้ง
SnapshotsClient.DataOrConflict.isConflict()
จะแสดงผลtrue
ด้วยวิธีนี้ เกมของคุณควรกลับไปยังขั้นตอนที่ 2 และทำตามขั้นตอนซ้ำเพื่อแก้ไขภาพรวมจนกว่า ความขัดแย้งจะได้รับการแก้ไข - หากไม่มีข้อขัดแย้ง
SnapshotsClient.DataOrConflict.isConflict()
จะแสดงผลfalse
และ ออบเจ็กต์Snapshot
เปิดให้เกมแก้ไขแล้ว
- หากมีข้อขัดแย้ง