تطوير ألعاب تناسب جميع الشاشات

عند تطوير لعبة على Android، من المهم توقُّع مجموعة متنوعة من تجارب اللاعبين المحتملة والتكيّف مع احتياجات اللاعبين المتعلقة بالتفاعل في الوقت الفعلي. من خلال توفير تجارب مختلفة للاعبين، يمكنك زيادة مرونة أسلوب اللعب، ما يساعدك على توسيع نطاق وصول لعبتك.

تشمل الاختلافات المحدّدة في تجربة اللاعب ما يلي:

  • أشكال الأجهزة: على الرغم من أنّ الهواتف توفّر تجربة أجهزة Android التقليدية، يمكن التفاعل مع الألعاب على أشكال أجهزة أخرى. يمكن لأجهزة ChromeOS تشغيل حاوية Android تعرض لعبتك. تتيح الأجهزة اللوحية التي تعمل بنظام التشغيل Android عدة مستويات مختلفة من الدقة. تتيح أجهزة Android TV تجارب أكثر تفصيلاً وغامرة. يمكن للاعبين محاكاة بيئة نوافذ متعددة باستخدام أداة توسيع الشاشة. وعند استخدام الأجهزة القابلة للطي، يمكن للاعبين تغيير حجم الشاشة أثناء جلسة اللعب.
  • طرق التفاعل: يمكن للاعبين إدخال البيانات من خلال لمس شاشة الجهاز، ولكن يمكنهم أيضًا استخدام الماوس أو لوحة اللمس أو لوحة المفاتيح أو وحدة التحكّم بدلاً من ذلك. بالإضافة إلى ذلك، يتيح توفُّر أدوات توسيع العرض والأجهزة القابلة للطي للاعبين تجربة لعبتك على شاشة أكبر، ما يجعل جلسات اللعب الأطول والواجهات الأكثر تعقيدًا أكثر جدوى.
  • التوافق مع الأجهزة: لا تتضمّن بعض الأجهزة التي تعمل بنظام التشغيل Android أجهزة أكثر شيوعًا في الأجهزة المحمولة، مثل كاميرا خلفية ونظام تحديد المواقع الجغرافية (GPS) وإمكانية الاتصال بالشبكة. يجب أن تتوافق لعبتك مع الأجهزة المتاحة وأن تتعامل بشكل سليم مع الحالات التي لا تتوفّر فيها ميزات معيّنة.

يقدّم هذا الدليل أفضل الممارسات المتعلّقة بتطوير لعبتك لتناسب أنواعًا مختلفة من الشاشات وتفاعلات المستخدمين. يقدّم هذا الدليل أيضًا اقتراحات حول تصميم لعبتك ووضع استراتيجية فعّالة للاختبار.

أفضل الممارسات في تصميم الألعاب

عند التخطيط لتصميم لعبتك وبنيتها، اتّبِع أفضل الممارسات الموضّحة في الأقسام التالية.

الاستجابة لتغييرات الإعدادات يدويًا

عندما يرصد نظام Android تغييرًا في الإعدادات، مثل تغيير في حجم الشاشة أو اتجاهها أو طريقة الإدخال، يعيد النظام تلقائيًا تشغيل النشاط الحالي. للحفاظ على الحالة داخل تطبيق أو لعبة، يستدعي النشاط تلقائيًا onSaveInstanceState() قبل إعادة التشغيل وonRestoreInstanceState() بعد إعادة التشغيل. ومع ذلك، تتطلّب هذه العملية إعادة تحميل جميع الخدمات والموارد المرتبطة بالنشاط. لمزيد من المعلومات حول هذا السلوك التلقائي، راجِع الدليل حول التعامل مع تغييرات الإعدادات.

تخضع جلسة اللعب النموذجية لعدة تغييرات في الإعدادات. إذا كانت لعبتك تتيح للنظام التعامل مع كل تغيير في الإعدادات، سيتم تدمير مشهد لعبتك وإعادة تشغيله مرارًا وتكرارًا، ما يؤدي إلى انخفاض أداء لعبتك. لهذا السبب، ننصحك بشدة بالتعامل مع تغييرات الإعدادات هذه بنفسك في لعبتك.

للتعرّف على كيفية إضافة منطق تغيير الإعدادات هذا إلى لعبتك، راجِع القسم حول كيفية إنشاء معالِجات مخصّصة لتغيير الإعدادات.

إنشاء بنية مرنة

لإتاحة لعبتك على أكبر عدد ممكن من الأجهزة، اتّبِع أفضل الممارسات التالية:

  • نشر "مجموعات حزمات تطبيق Android" بدلاً من حِزم APK الفردية تتيح لك حِزم تطبيقات Android تجميع عناصر مختلفة الدقة ونماذج بنى مختلفة، مثل x86 وARM، في عنصر واحد. والأفضل من ذلك أنّ "حِزم تطبيقات Android" تتيح حدودًا أعلى للحجم في لعبتك، إذ يمكن أن يصل حجم كل حزمة APK أساسية إلى 150 ميغابايت، ويمكن أن يصل حجم الحزمة نفسها إلى عدة غيغابايت.
  • إتاحة استخدام بنى x86 تساعد هذه الخطوة في تحسين أداء لعبتك على الأجهزة التي لا تتوافق مع ARM، لأنّ هذه الأجهزة يمكنها الآن تنفيذ التعليمات بدون الحاجة إلى ترجمتها أولاً.

إتاحة استخدام Vulkan

من خلال توفير التوافق مع Vulkan، يمكن أن تحقق لعبتك أداءً أفضل في الرسومات. تتوافق معظم الأجهزة مع واجهة برمجة التطبيقات للرسومات هذه.

إنشاء معالِجات مخصّصة لتغيير الإعدادات

لتحديد أنواع تغييرات الإعدادات التي تعالجها لعبتك بنفسها، أضِف السمة android:configChanges إلى كل عنصر <activity> في ملف البيان يمثّل شاشة أو واجهة معقّدة.

يوضّح مقتطف الرمز التالي كيفية الإشارة إلى أنّ لعبتك تتعامل مع التغييرات في حجم الشاشة واتجاهها وأسلوب الإدخال:

<activity ...
    android:configChanges="screenSize|orientation|keyboard|keyboardHidden">
</activity>

عند حدوث تغييرات في الإعدادات المحدّدة، يستدعي النظام الآن طريقة مختلفة، وهي onConfigurationChanged(). ضِمن هذه الطريقة، أضِف منطقًا لتعديل واجهة مستخدم لعبتك:

التعامل مع تغييرات إعدادات الشاشة

تتعامل لعبتك مع تغييرات حجم الشاشة واتجاهها يدويًا عندما تضمّن القيمتين screenSize وorientation على التوالي في السمة android:configChanges. يمكنك استخدام هذه القيم الجديدة لتعديل محتوى المشهد ومناطق إدخال اللاعب. للحصول على إرشادات حول كيفية تصميم تخطيط لعبتك لتسهيل تحديثها، اطّلِع على دليل توافق التطبيق مع أحجام الشاشات المختلفة.

في تنفيذ onConfigurationChanged() في لعبتك، استخدِم العنصر Configuration الذي تم تمريره وعنصر Display الخاص بمدير النوافذ لتحديد القيم المعدَّلة لحجم الشاشة واتجاه الشاشة على التوالي.

يوضّح مقتطف الرمز التالي كيفية الحصول على حجم الشاشة واتجاهها المعدَّلين في لعبتك:

Kotlin

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    val density: Float = resources.displayMetrics.density
    val newScreenWidthPixels = (newConfig.screenWidthDp * density).toInt()
    val newScreenHeightPixels = (newConfig.screenHeightDp * density).toInt()

    // Get general orientation; either Configuration.ORIENTATION_PORTRAIT or
    // Configuration.ORIENTATION_LANDSCAPE.
    val newScreenOrientation: Int = newConfig.orientation

    // Get general rotation; one of: ROTATION_0, ROTATION_90, ROTATION_180,
    // or ROTATION_270.
    val newScreenRotation: Int = windowManager.defaultDisplay.rotation
}

Java

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    float density = getResources().getDisplayMetrics().density;
    int newScreenWidthPixels = (int) (newConfig.screenWidthDp * density);
    int newScreenHeightPixels = (int) (newConfig.screenHeightDp * density);

    // Get general orientation; either Configuration.ORIENTATION_PORTRAIT or
    // Configuration.ORIENTATION_LANDSCAPE.
    int newScreenOrientation = newConfig.orientation;

    // Get general rotation; one of: ROTATION_0, ROTATION_90, ROTATION_180,
    // or ROTATION_270.
    int newScreenRotation = getWindowManager().getDefaultDisplay()
            .getRotation();
}

يُرجى العِلم أنّ تغيير وضع الجهاز القابل للطي يؤدي إلى تغيير الإعدادات، حتى إذا كان تطبيقك يعمل في وضع ملء الشاشة. نتيجةً لذلك، قد يحتاج تطبيقك إلى التعامل مع التغييرات في حجم الشاشة أو كثافة البكسل إذا طوى المستخدم الجهاز أو فتحه أثناء تشغيل لعبتك.

جودة الشاشة الخاصة باللعبة

توضّح الأقسام التالية كيفية ضبط طريقة تفاعل لعبتك مع التغييرات في حجم الشاشة أو اتجاهها، وذلك حسب خصائص لعبتك:

وضع ملء الشاشة

في بعض المنصات، مثل ChromeOS، يمكن عرض تطبيقات وألعاب Android في نوافذ وتغيير حجمها تلقائيًا. إذا كان من المفترض أن تعمل لعبتك دائمًا في وضع ملء الشاشة، يمكنك ضبط السمة android:resizeableActivity على false في أحد عناصر <activity>، كما هو موضّح في مقتطف الرمز التالي:

<activity ...
    android:resizeableActivity="false">
</activity>

يمكنك أيضًا ضبط السمة android:resizeableActivity على false لمنع حدوث تغييرات في الإعدادات استنادًا إلى الحجم. ومع ذلك، إذا لم تكن لعبتك تعمل دائمًا في وضع ملء الشاشة، يجب إضافة هذه السمة كحل مؤقت لأغراض الاختبار فقط.

اتجاه الشاشة

إذا كانت لعبتك تعتمد على اتجاه محدّد لأدوات الاستشعار في الجهاز، حدِّد قيمة android:screenOrientation في نشاط لعبتك، كما هو موضّح في مقتطف الرمز البرمجي التالي. يساعد هذا الإعداد في منع قلب مشهد في لعبتك بشكل غير متوقّع.

<activity ...
    android:screenOrientation="landscape">
</activity>

سمات الشاشة الخاصة بالجهاز

توضّح الأقسام التالية كيفية التعامل مع تغييرات الإعدادات المستندة إلى الشاشة مع مراعاة الخصائص المحدّدة التي تتوفّر في بعض الأجهزة.

نسبة العرض إلى الارتفاع

تتوافق بعض الأجهزة مع نِسب عرض إلى ارتفاع مختلفة. على سبيل المثال، تم تصميم الأجهزة القابلة للطي لتتوافق مع نسبة عرض إلى ارتفاع تبلغ 21:9 عندما تكون في وضع الطي. للتعامل مع هذا التنوّع المحتمل في نسبة العرض إلى الارتفاع، اتّخِذ إجراءً واحدًا على الأقل مما يلي:

  • استهداف الإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث
  • إتاحة تغيير حجم المشهد والواجهة في لعبتك اضبط android:resizeableActivity على true على الأجهزة التي تعمل بالإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات) والإصدارات الأحدث.
  • تحديد الحدّ الأقصى لنسبة العرض إلى الارتفاع المسموح بها في السمة <meta-data> المرتبطة بلعبتك، اضبط قيمة android.max_aspect على 2.4، كما هو موضّح في مقتطف الرمز التالي. يُرجى العِلم أنّ نسب العرض إلى الارتفاع الأكبر من النسبة التي حدّدتها ستؤدي إلى ظهور اللعبة مُعد للعرض على شاشة عريضة أفقيًا ضمن الشاشة.

    <application>
    <meta-data android:name="android.max_aspect"
               android:value="2.4" />
    </application>

أنشطة متعدّدة مرئية في الوقت نفسه

تتيح العديد من الأجهزة الحديثة مجموعة متنوعة من تصميمات الشاشة، بما في ذلك الشاشة المقسّمة ووضع &quot;نافذة ضمن النافذة&quot; ومساحات العرض الكبيرة. عند استخدام أحد هذه التصاميم، يمكن للنظام عرض أنشطة متعددة في الوقت نفسه.

على الأجهزة التي تعمل بالإصدار Android 9 (مستوى واجهة برمجة التطبيقات 28) أو الإصدارات الأحدث، يمكن استئناف جميع الأنشطة المرئية في المقدّمة في الوقت نفسه. ولكي تعمل هذه الميزة، يجب أن توافق كل من لعبتك والشركة المصنّعة للجهاز على إتاحة هذه الوظيفة. يمكنك إضافة إمكانية استخدام هذه الميزة في لعبتك من خلال ضبط android.allow_multiple_resumed_activities على true في ملف بيان اللعبة، كما هو موضّح في المقتطف التالي:

<application>
    <meta-data android:name="android.allow_multiple_resumed_activities"
               android:value="true" />
</application>

يمكنك بعد ذلك اختبار لعبتك على أجهزة مختلفة لمعرفة أيّها يوفّر دعم المصنّع الأصلي للجهاز اللازم لتعمل ميزة "استئناف متعدّد" بشكل صحيح.

لمزيد من المعلومات حول ضبط لعبتك لتظهر كجزء من شاشة عرض بنوافذ متعدّدة، اطّلِع على الدليل حول كيفية إضافة ميزة النوافذ المتعدّدة.

التعامل مع أنواع مختلفة من نماذج التفاعل

تتعامل لعبتك مع توفّر لوحة المفاتيح وإمكانية استخدامها يدويًا عند تضمين القيمتَين keyboard وkeyboardHidden على التوالي في السمة android:configChanges. يمكنك استخدام هذه القيم الجديدة لتعديل طريقة الإدخال الأساسية في لعبتك.

عند ضبط إعدادات لعبتك لتتيح أنواعًا متعددة من بيانات أدخلها المستخدم، يجب مراعاة ما يلي:

  • رصد طرق الإدخال بدلاً من الأجهزة الفردية: ويسهّل هذا النهج تحسين تجربة اللاعبين بدون التركيز بشكل كبير على الجهاز الذي يستخدمونه.
  • أدرِج السمة keyboardHidden في قائمة التغييرات التي يتم التعامل معها يدويًا في الإعدادات. بهذه الطريقة، يمكن أن تتتبّع لعبتك الوقت الذي تكون فيه لوحة المفاتيح متصلة بالجهاز ولكن لا يمكن استخدامها.
  • تحديد طرق الإدخال المتوفّرة حاليًا لإجراء ذلك، استدعِ الدالة getInputDeviceIds() عند بدء تشغيل اللعبة وبعد كل تغيير في الإعدادات.

    يمكنك غالبًا تحديد الطريقة التي يخطّط اللاعب للتفاعل بها مع لعبتك استنادًا إلى جهاز الإدخال المفضّل لديه:

    • يستخدم اللاعبون عادةً لوحة مفاتيح أو ذراع التحكّم في الألعاب لتنفيذ تسلسلات سريعة من الضغط على الأزرار.
    • يستخدم اللاعبون عادةً شاشة تعمل باللمس أو لوحة لمس لتنفيذ إيماءات أكثر تعقيدًا.
    • يستخدم اللاعبون عادةً الماوس لإدخال البيانات بدقة أعلى.

تقدّم الأقسام التالية أفضل الممارسات لأنواع معيّنة من أجهزة الإدخال.

لوحة المفاتيح

عند إنشاء تخطيط لوحة مفاتيح للعبتك، يجب مراعاة طريقة تنقّل اللاعب في مشهد معيّن، بالإضافة إلى طريقة تفاعله مع إعدادات اللعبة.

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

يجب أن يتمكّن اللاعبون أيضًا من فتح قوائم لعبتك والتنقّل فيها باستخدام لوحة المفاتيح. المفتاح Esc هو عملية ربط شائعة لإيقاف مشهد مؤقتًا وعرض قائمة اللعبة.

لمزيد من المعلومات حول إتاحة إدخال البيانات باستخدام لوحة المفاتيح في لعبتك، يُرجى الاطّلاع على الدليل حول كيفية إتاحة التنقّل باستخدام لوحة المفاتيح والدليل حول كيفية التعامل مع الإجراءات التي تتم باستخدام لوحة المفاتيح.

ذراع التحكّم في الألعاب

لمزيد من المعلومات حول معالجة إدخال وحدة التحكّم في لعبتك، اطّلِع على الدليل حول كيفية توفير التوافق مع أذرع التحكّم في الألعاب.

الماوس أو لوحة اللمس

إذا كانت لعبتك تتيح للاعبين إدخال البيانات باستخدام ماوس أو لوحة لمس، ضَع في اعتبارك أنّ اللاعبين يتفاعلون مع الجهاز بطرق أخرى غير لعبتك. يُرجى العِلم أنّه عند طلب تسجيل المؤشر، سيتم توجيه جميع إدخالات الماوس إلى لعبتك. لذلك، بعد أن تحصل لعبتك على المعلومات التي تحتاج إليها، يجب إيقاف ميزة "التقاط المؤشر" لكي يستعيد اللاعبون إمكانية التحكّم العادي في الماوس على أجهزتهم.

على الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك استخدام واجهة برمجة التطبيقات MouseCapture للمساعدة في عملية التقاط المؤشر. في الألعاب التي تتفاعل مع الإدخال عالي الدقة، يمكنك الحصول على الإحداثيات الحالية للمؤشر من خلال استدعاء الطريقتَين getX() وgetY().

للحصول على معلومات إضافية حول إتاحة استخدام الماوس ولوحة اللمس في لعبتك، اطّلِع على الدليل حول كيفية تتبُّع حركات اللمس والمؤشر بالإضافة إلى الدليل حول كيفية التعامل مع إيماءات اللمس المتعدد.

اختبار لعبتك

قبل إطلاق لعبتك، اختبِر طريقة استجابتها لتغييرات الإعدادات من خلال إكمال الخطوات الموضّحة في الأقسام التالية.

تعديل خطة الاختبار

عند التحقّق من صحة وظائف لعبتك، أدرِج حالات الاختبار التالية:

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

ننصحك أيضًا بتعديل نظام مراقبة الجودة في لعبتك لتتمكّن من تحسينها لتناسب مجموعة أكبر من تجارب اللاعبين.

للاطّلاع على أفضل الممارسات المتعلّقة باختبار لعبتك، راجِع دليل أساسيات الاختبار.

استخدام أدوات الاختبار وتصحيح الأخطاء

يمكنك إجراء الاختبارات باستخدام مجموعة متنوعة من الأدوات التي تتيحها المنصة: