إضافة الألعاب المحفوظة إلى لعبتك

يشرح لك هذا الدليل كيفية حفظ وتحميل بيانات مستوى تقدّم اللاعب في اللعبة باستخدام خدمة الألعاب المحفوظة في تطبيق C++. يمكنك استخدام هذه الصفحة خدمة لتحميل وحفظ مستوى تقدم اللاعبين تلقائيًا في أي وقت أثناء اللعب. يمكن لهذه الخدمة أيضًا السماح للّاعبين بتوجيه تشغيل إلى حساب مستخدم. لتحديث أو استعادة لعبة حفظ حالية أو إنشاء لعبة جديدة.

قبل البدء

إذا لم تكن قد فعلت ذلك بالفعل، فقد تجد أنه من المفيد مراجعة مفاهيم ألعاب محفوظة في الألعاب:

قبل بدء الترميز باستخدام واجهة برمجة تطبيقات "الألعاب المحفوظة":

تنسيقات البيانات والتوافق عبر الأنظمة الأساسية

يجب أن تكون بيانات "الألعاب المحفوظة" التي يتم حفظها في خوادم 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. أولاً، افتح اللقطة التي نريد تعديلها، وتأكد من إزالة جميع التعارضات حله عن طريق اختيار القاعدة.

    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());
    

    تحتوي مَعلمة البيانات على جميع بيانات الألعاب المحفوظة التي تخزنها. يشمل التغيير أيضًا بيانات وصفية إضافية محفوظة للعبة، مثل الوقت. التي لعبتها ووصفًا للّعبة المحفوظة.

إذا اكتملت العملية بنجاح، يمكن للّاعبين مشاهدة اللعبة المحفوظة في واجهة مستخدم اختيار الألعاب المحفوظة.