במדריך הזה נסביר איך לשמור ולטעון את נתוני ההתקדמות של השחקן במשחק באמצעות השירות 'משחקים שמורים' באפליקציה ב-C++. אתם יכולים להשתמש בשירות הזה כדי לטעון ולשמור באופן אוטומטי את ההתקדמות של השחקנים במשחק בכל שלב במהלך המשחק. השירות הזה יכול גם לאפשר לשחקנים להפעיל ממשק משתמש כדי לעדכן או לשחזר משחק שמור קיים, או ליצור משחק חדש.
לפני שמתחילים
אם עדיין לא עשיתם זאת, מומלץ לעיין במושגי המשחקים של 'משחקים שמורים'.
לפני שמתחילים לכתוב קוד באמצעות Saved Games API:
- מתקינים את Play Games SDK ב-C++.
- הגדרת סביבת הפיתוח של C++
- הורדה ובדיקה של דוגמת הקוד ב-C++
- מפעילים את השירות 'משחקים שמורים' ב-Google Play Console.
פורמטים של נתונים ותאימות בפלטפורמות שונות
נתוני המשחקים השמורים ששומרים בשרתים של 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);
}
בדוגמה הבאה מוסבר איך להציג את ממשק המשתמש של המשחקים השמורים כברירת מחדל, ולטפל בבחירת ממשק המשתמש של השחקן:
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
גדול ממספר קובצי ה-snapshot שהמשתמש יצר בפועל, ממשק המשתמש של Snapshot שמוגדר כברירת מחדל יציג לשחקנים לחצן ליצירת משחק שמאוחסן ב-save חדש, במקום לאפשר להם לבחור משחק קיים. (כשהוא מוצג, הלחצן נמצא בחלק התחתון של ממשק המשתמש). כשמשתמש לוחץ על הלחצן הזה, התגובה 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.
ביצוע מיזוג מותאם אישית
אם ציינתם את הערך 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()
כדי לשמור את השינויים במשחק.
בדוגמה הבאה מוסבר איך ליצור שינוי ולבצע השמירה של משחק.
קודם פותחים את קובץ snapshot שרוצים לערוך, ובוחרים את הבסיס כדי לוודא שכל העימותים נפתרו.
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();
לבסוף, מבצעים commit לשינויים שנשמרו במשחק.
gpg::SnapshotManager::CommitResponse commitResponse = service_->Snapshots().CommitBlocking(metadata, metadata_change, SetupSnapshotData());
הפרמטר data מכיל את כל נתוני המשחק השמורים שאתם מאחסנים. השינוי מכיל גם מטא-נתונים נוספים של המשחק השמור, כמו משך הזמן שבו שיחקתם בו ותיאור של המשחק השמור.
אם פעולת השמירה הושלמה בהצלחה, השחקנים יוכלו לראות את המשחק השמור בממשק המשתמש לבחירת משחקים שמורים.