دراسة حالة - تغيير حجم ألعاب HTML5 تلقائيًا

مقدمة

في صيف 2010، أنشأنا لعبة الرمال الرملية (Sand Trap)، وهي لعبة شاركناها في مسابقة حول ألعاب HTML5 للهواتف الجوالة. لكن معظم الهواتف الجوّالة إما عرضت جزءًا فقط من اللعبة أو جعلت اللعبة صغيرة جدًا - مما يجعلها غير قابلة للتشغيل على الإطلاق. لذا، اضطررنا إلى تعديل اللعبة بسلاسة لتتوافق مع أي حلّ ممكن. بعد القليل من إعادة البرمجة واستخدام الأفكار الموضّحة في هذه المقالة، أطلِقنا لعبة تطوّرت على أي متصفّح حديث، سواء كانت تُعرض على كمبيوتر مكتبي أو جهاز جوّال.

لقطة شاشة بملء الشاشة في thwack
لقطة شاشة لـ thwack Small في نافذة المتصفح

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

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

تحضير الصفحة

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

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

<div id="gameArea">
  <canvas id="gameCanvas"></canvas>
  <div id="statsPanel"></div>
</div>

بمجرد حصولك على بنية أساسية للمستند، يمكنك إعطاء هذه العناصر بعض خصائص CSS لإعدادها لتغيير الحجم. يتم التعامل مع العديد من خصائص CSS لـ "gameArea" مباشرةً باستخدام JavaScript، ولكن لكي تعمل هذه الخصائص، يمكنك إعداد بعض خصائص CSS الأخرى التي تبدأ بكتلة gameArea الرئيسية div:

#gameArea {
  position: absolute;
  left:     50%;
  top:      50%;
}

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

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

في هذا المثال، ابدأ بعرض منطقة اللعبة 300 بكسل وعرضها 400 بكسل. تغطي اللوحة مساحة اللعبة بالكامل، كما تظهر لوحة إحصاءات شبه شفافة على طول الجزء السفلي بطول 24 بكسل، كما هو موضح في الشكل 1.

أبعاد عناصر gameArea الفرعية بالبكسل
الشكل 1: أبعاد عناصر gameArea الفرعية بالبكسل

عند ترجمة هذه القيم إلى نسب مئوية، يصبح عرض اللوحة% 100 وارتفاعها بنسبة% 100 (في منطقة الألعاب، وليس في النافذة). تكون القسمة على 24 على 300 ارتفاع لوحة الإحصاءات بنسبة 8%، وبما أنها ستغطي الجزء السفلي من منطقة الألعاب، سيبلغ عرضها أيضًا 100%، كما هو موضح في الشكل 2.

أبعاد عناصر GameArea الفرعية بالنسب المئوية
الشكل 2: أبعاد عناصر gameArea الفرعية بالنسب المئوية

الآن وبعد أن حددت أبعاد منطقة اللعبة وعناصرها الفرعية، يمكنك تجميع خصائص CSS للعنصرين الداخليين معًا على النحو التالي:

#gameCanvas {
  width: 100%;
  height: 100%;
}
#statsPanel {
  position: absolute;
  width: 100%;
  height: 8%;
  bottom: 0;
  opacity: 0.8;
}

تغيير حجم اللعبة

أنت الآن جاهز لإنشاء دالة للتعامل مع النافذة التي يتم تغيير حجمها. أولاً، احصل على مرجع إلى عنصر المستند gameArea الرئيسي.

var gameArea = document.getElementById('gameArea');

نظرًا لأنك غير معني بشأن العرض أو الارتفاع الدقيق، فإن المعلومة التالية التي تحتاج إلى تعيينها هي نسبة العرض إلى الارتفاع. باستخدام المرجع السابق لمنطقة لعبة يبلغ عرضها 400 بكسل وارتفاع 300 بكسل، يمكنك أيضًا ضبط نسبة العرض إلى الارتفاع على 4 وحدات عرضًا و3 وحدات ارتفاع.

var widthToHeight = 4 / 3;

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

var newWidth = window.innerWidth;
var newHeight = window.innerHeight;

مثلما حددت نسبة العرض إلى الارتفاع التي تريدها، يمكنك الآن تحديد نسبة العرض الحالية للنافذة إلى الارتفاع:

var newWidthToHeight = newWidth / newHeight;

ويتيح لك هذا تحديد ما إذا كنت تريد أن تملأ اللعبة الشاشة عموديًا أو أفقيًا، كما هو موضح في الشكل 3.

ملاءمة عنصر gameArea في النافذة مع الحفاظ على نسبة العرض إلى الارتفاع
الشكل 3: ملاءمة عنصر gameArea بالنافذة مع الحفاظ على نسبة العرض إلى الارتفاع

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

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

if (newWidthToHeight > widthToHeight) {
  // window width is too wide relative to desired game width
  newWidth = newHeight * widthToHeight;
  gameArea.style.height = newHeight + 'px';
  gameArea.style.width = newWidth + 'px';
} else { // window height is too high relative to desired game height
  newHeight = newWidth / widthToHeight;
  gameArea.style.width = newWidth + 'px';
  gameArea.style.height = newHeight + 'px';
}

الآن وبعد تعديل عرض مساحة اللعبة وارتفاعها، يجب توسيط الأمور من خلال وضع هامش سالب في الجزء العلوي يمثل نصف الارتفاع وعلى اليسار بنصف العرض. تذكَّر أنّ لغة CSS تضع الزاوية العلوية اليمنى من قسم gameArea في منتصف النافذة، وبالتالي يؤدي هذا الإجراء إلى توسيط منطقة اللعبة في النافذة:

gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';

كما يمكنك ضبط حجم الخط تلقائيًا. إذا كنت تستخدم كل العناصر الفرعية em، يمكنك ببساطة ضبط سمة fontSize CSS لكتلة gameArea على قيمة يتم تحديدها حسب حجمها.

gameArea.style.fontSize = (newWidth / 400) + 'em';

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

var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;

لذلك قد تبدو دالة تغيير الحجم المكتملة كما يلي:

function resizeGame() {
    var gameArea = document.getElementById('gameArea');
    var widthToHeight = 4 / 3;
    var newWidth = window.innerWidth;
    var newHeight = window.innerHeight;
    var newWidthToHeight = newWidth / newHeight;
    
    if (newWidthToHeight > widthToHeight) {
        newWidth = newHeight * widthToHeight;
        gameArea.style.height = newHeight + 'px';
        gameArea.style.width = newWidth + 'px';
    } else {
        newHeight = newWidth / widthToHeight;
        gameArea.style.width = newWidth + 'px';
        gameArea.style.height = newHeight + 'px';
    }
    
    gameArea.style.marginTop = (-newHeight / 2) + 'px';
    gameArea.style.marginLeft = (-newWidth / 2) + 'px';
    
    var gameCanvas = document.getElementById('gameCanvas');
    gameCanvas.width = newWidth;
    gameCanvas.height = newHeight;
}

والآن، تريد إجراء هذه التعديلات تلقائيًا كلما يتم تغيير حجم النافذة أو يتم تغيير اتجاه الشاشة في حالة الأجهزة المحمولة. التعامل مع هذه الأحداث من خلال جعلها تستدعي دالة renameGame() على النحو التالي:

window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);

إذا تم تغيير حجم النافذة بشكل كبير جدًا أو كان اتجاه الشاشة رأسيًا، يعني ذلك أنّ عرض النافذة يكون بنسبة 100%، وإذا تم تغيير حجم النافذة بشكل كبير جدًا أو كان اتجاه الشاشة أفقيًا، سيكون ارتفاع النافذة بنسبة 100%. ويتم تحديد حجم البُعد المتبقي وفقًا لنسبة العرض إلى الارتفاع المحددة مسبقًا من العرض إلى الارتفاع.

ملخّص

استخدمت Gopherwood Studios إصدارات من هذا الهيكل لجميع ألعاب HTML5 وأثبتت أنها مفيدة للغاية لاستيعاب عدة درجات للشاشات والعديد من الأجهزة الجوالة. بالإضافة إلى ذلك، بمساعدة متصفح بملء الشاشة، تمنح هذه الألعاب ألعاب الويب تجربة غامرة تشبه ألعاب سطح المكتب التقليدية أكثر من العديد من الألعاب المستندة إلى المتصفحات. ونتطلع إلى مزيد من الابتكارات في ألعاب الويب في ظل التطور المستمر لتقنيات HTML5 والويب.