يوضّح لك هذا الدليل كيفية حفظ بيانات مستوى تقدّم اللاعب في اللعبة وتحميلها باستخدام خدمة "الألعاب المحفوظة" في تطبيق C++. يمكنك استخدام هذه الخدمة لتحميل م��توى تقدّم اللاعب في اللعبة وحفظه تلقائيًا في أي وقت أثناء اللعب. يمكن لهذه الخدمة أيضًا أن تمكّن اللاعبين من عرض واجهة مستخدم لتحديث أو استعادة لعبة حفظ حالية أو إنشاء لعبة جديدة.
قبل البدء
ننصحك بمراجعة مفاهيم ألعاب "حفظ التقدم في الألعاب" إذا لم يسبق لك ذلك.
قبل بدء الترميز باستخدام واجهة برمجة التطبيقات Saved Games API:
- ثبِّت حزمة تطوير البرامج (SDK) لألعاب Play التي تستخدم لغة C++.
- إعداد بيئة تطوير C++
- نزِّل نموذج رمز C++ وراجِعه.
- فعِّل خدمة "الألعاب المحفوظة" في Google Play Console.
تنسيقات البيانات والتوافق مع جميع المنصات
يجب أن تكون بيانات "ألعاب Google Play المحفوظة" التي تحفظها ��لى خوادم 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()
لحفظ التغييرات التي أجريتها على
اللعبة المحفوظة.
يوضّح المثال التالي كيفية إجراء تغيير وحفظ ملف لعبة.
أولاً، افتح اللقطة التي نريد تعديلها، وتأكد من حل جميع التعارضات عن طريق اختيار القاعدة.
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();
أخيرًا، احفظ التغييرات التي أجريتها على اللعبة.
gpg::SnapshotManager::CommitResponse commitResponse = service_->Snapshots().CommitBlocking(metadata, metadata_change, SetupSnapshotData());
تحتوي مَعلمة data على جميع بيانات حفظ الألعاب التي تخزّنها. يتضمّن التغيير أيضًا بيانات وصفية إضافية عن اللعبة المحفوظة، مثل المدّة التي تم فيها تشغيل اللعبة ووصف لها.
إذا اكتملت عملية الحفظ بنجاح، يمكن للاعبين الاطّلاع على اللعبة المحفوظة في واجهة مستخدم اختيار "الألعاب المحفوظة".