הוספת משחקים שמורים למשחק

במדריך הזה נסביר איך לשמור ולטעון את נתוני ההתקדמות של השחקן במשחק באמצעות השירות 'משחקים שמורים' באפליקציה ב-C++‎. אתם יכולים להשתמש בשירות הזה כדי לטעון ולשמור באופן אוטומטי את ההתקדמות של השחקנים במשחק בכל שלב במהלך המשחק. השירות הזה יכול גם לאפשר לשחקנים להפעיל ממשק משתמש כדי לעדכן או לשחזר משחק שמור קיים, או ליצור משחק חדש.

לפני שמתחילים

אם עדיין לא עשיתם זאת, מומלץ לעיין במושגי המשחקים של 'משחקים שמורים'.

לפני שמתחילים לכתוב קוד באמצעות 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);
}

בדוגמה הבאה מוסבר איך להציג את ממשק המשתמש של המשחקים השמורים כברירת מחדל, ולטפל בבחירת ממשק המשתמש של השחקן:

  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() כדי לשמור את השינויים במשחק.

בדוגמה הבאה מוסבר איך ליצור שינוי ולבצע השמירה של משחק.

  1. קודם פותחים את קובץ 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
            }
          });
    
  2. בשלב הבא, יוצרים שינוי במשחק השמור שכולל את נתוני התמונה ששימשו לתמונת השער:

    gpg::SnapshotMetadataChange::Builder builder;
    gpg::SnapshotMetadataChange metadata_change =
        builder.SetDescription("CollectAllTheStar savedata")
                 .SetCoverImageFromPngData(pngData).Create();
    
  3. לבסוף, מבצעים commit לשינויים שנשמרו במשחק.

    gpg::SnapshotManager::CommitResponse commitResponse =
        service_->Snapshots().CommitBlocking(metadata, metadata_change, SetupSnapshotData());
    

    הפרמטר data מכיל את כל נתוני המשחק השמורים שאתם מאחסנים. השינוי מכיל גם מטא-נתונים נוספים של המשחק השמור, כמו משך הזמן שבו שיחקתם בו ותיאור של המשחק השמור.

אם פעולת השמירה הושלמה בהצלחה, השחקנים יוכלו לראות את המשחק השמור בממשק המשתמש לבחירת משחקים שמורים.