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

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

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

אם עדיין לא עשיתם זאת, כדאי לעיין בקונספטים של משחקים שמורים.

לפני שמתחילים לתכנת בעזרת ה-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 גדול יותר ממספר תמונות המצב שהמשתמש יצר בפועל, ברירת המחדל של ממשק המשתמש מספקת לשחקנים לחצן ליצירת משחק שמירה חדש, במקום לבחור במשחק קיים. (כש הלחצן מוצג, הוא מופיע בחלק התחתון של ממשק המשתמש). כשהשחקן לוחץ על הלחצן, התגובה 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. לסיום, מבצעים את השינויים השמורים במשחק.

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

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

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