تبسيط البرمجة ب JavaScript باستخدام jQuery


الدرس: لعبة في jQuery


الصفحة السابقة
انتظر الكثيرون منك فصلاً مخصصًا لصنع الألعاب في jQuery . حسنا ، أنت هنا! سوف تتعلم كيفية:
  • عرض ديكور متحرك لإيهام المشاهد أن هنالك كائنات تتحرك ؛
  • نقل الكائنات على الشاشة باستخدام مفاتيح الأسهم على لوحة المفاتيح ؛
  • إدارة طبقات الرسم متعددة
  • كشف الاصطدامات
  • إضافة الأصوات.
مستعد؟ دعنا نذهب!

المستند الأساسي


قبل الذهاب إلى أبعد من ذلك ، سأريك كيف ستبدو اللعبة ، انظر إلى الشكل التالي للحصول على لمحة عنها.
jQuery web
اللعبة في صيغتها النهائية
يتم تمرير الطريق من الأسفل إلى الأعلى. يقوم المشغل بقيادة السيارة الصفراء ويجب تجنب السيارات الحمراء التي تظهر بشكل عشوائي على الشاشة. السيارة الصفراء تتحرك مع مفاتيح لوحة المفاتيح يمين و يسار. منطقة اللعبة ليست سوى علامة <div> نضع فيها عناصر الرسوم المختلفة:
  • قسمين الطريق #fond1 و #fond2 ، سواء الطبقة .fond .
  • السيارة الصفراء #vj .
  • السيارة الحمراء #vr .
أقترح عليك تنزيل الصور التي استخدمتها ، ولكن يمكنك بالطبع التقاط صورك الخاصة.
jQuery web
الخلفية: "route.png"
jQuery web
السيارة الصفراء: "vj.png"
jQuery web
السيارة الحوراء: "vr.png"
يتم عرض المعلومات النصية على مساحة اللعبة باستخدام علامة <span> . إليك كود HTML المستخدم:

Collisions : <span id="info">0</span>
<div id="jeu">
  <img id="fond1" class="fond" src="route.png">
  <img id="fond2" class="fond" src="route.png">
  <img id="vj" src="vj.png"> <!—السيارة الصفراء -->
  <img id="vr" src="vr.png"> <!—السيارة الحمراء -->
</div>
يتم تنسيق هذه العناصر باستخدام عدد قليل من عبارات CSS . #jeu حجم الملعب 400 × 400 بكسل. إنه محاط بحدود سوداء متواصلة بسماكة 2 بكسل. لأنه سيتم عرض صورتين واحدة دون الأخرى ، overflow تتم تهيئة الخاصية hidden لإخفاء أشرطة التمرير. المواقع داخل منطقة اللعب نسبية.

#jeu{
  width: 400px;
  height: 400px;
  border: 2px black solid;
  overflow: hidden;
  position: relative;
}
يتم وضع الصور التي تمثل المسار نسبيًا z-index وتتم تهيئتها إلى 10. أما بالنسبة لصور السيارات ، فيتم وضعها بشكل مطلق z-index ويتم تهيئتها بقيم أخرى. سوف تفهم لماذا من خلال قراءة المزيد

.fond{
  margin-bottom:-5px;
  z-index: 10;
  position: relative;
}
#vj{
  z-index: 100;
  position: absolute;
  top: 10px;
  left: 48px;
}
#vr{
  z-index: 80;
  position: absolute;
  top: -200px;
  left: 0px;
}
في الفصول السابقة ، عبرنا بالفعل خاصية CSS z-index . ما زلت أتذكر أن هذه الخاصية تتيح لك تكديس عناصر متعددة فوق بعضها البعض. العنصر الأكثر تواجدًا في المقدمة هو العنصر ذي z-index الأعلى. وعلى العكس ، فإن العنصر الأكثر تواجدًا في الخلفية هو العنصر الأكثر z-index ضعفًا ، كما هو موضح في الشكل التالي.
jQuery web
يتم تكديس العناصر وفقًا لخاصية z-index الخاصة بها
في الكود الذي نعمل عليه ، الطريق z-index يساوي 10 ، والسيارة الحمراء z-index تساوي 80 ، والسيارة الصفراء z-index تساوي 100. وستكون السيارة الصفراء في المقدمة ، والطريق الخلفي وسيتم عرض السيارة الحمراء فوق الطريق ، ولكن أسفل السيارة الصفراء إذا كنت لا تعرف كيفية تجنبها.
هذا كل شيء: بنية المستند وتخطيطه موجودان الآن! يبقى فقط (!) لكتابة بضعة أسطر من jQuery لوضع كل هذا في الحركة.

إدارة التحركات


إنشاء ديكور متحرك
يجب أن ينتقل الطريق من أسفل إلى أعلى منطقة اللعب ، هل لديك أي فكرة عن الطريقة التي يجب استخدامها؟ الطريقة animate() ، بالطبع!
حسنًا ، animate() ستسمح لي هذه الطريقة بتحريك الطريق للأعلى ، لكن كيف أقوم بإنشاء حلقة العرض بنفسها حتى ينتهي الطريق دون توقف؟
ستؤدي نصيحتان إلى هذه النتيجة:
  1. عن طريق إدراج استدعاء الأسلوب animate() في دالة وإعادة تنفيذ هذه الوظيفة عبر وظيفة رد الاتصال بالطريقة animate() ، يتم الحصول على حلقة لا نهاية لها.
  2. من خلال استعادة الموضع الأولي لصور الفصل .fond في وظيفة رد الاتصال بالطريقة animate() ، يمكن بدء حركة تصاعدية جديدة.
هنا هو الكود المستخدم:

function deplace()
{
  $('.fond').animate({
    top: '-=360'
  },
  1000,
  'linear',
  function(){
    $('.fond').css('top', 0);
    deplace();
  });
}
في هذا الكود ، يتم نقل الصورتين للمسار خطيًا للأعلى بمقدار 360 بكسل في 1000 مللي ثانية. عند اكتمال هذه الخطوة ، يتم تنفيذ وظيفة رد الاتصال. يتم إرجاع الصور إلى موضعها الأصلي deplace() ويتم تنفيذ الوظيفة مرة أخرى.
لماذا استخدام صورتين؟
تحرك الطريقة animate() الإطار الأول 360 بكسل للأعلى. بإضافة صورة ثانية مماثلة لاستمرارها ، فإنها تتجنب ظهور منطقة بيضاء في الجزء السفلي من منطقة التشغيل ، كما في الشكل التالي.
jQuery web
الصورة الثانية تضمن استمرارية الطريق
فقط قم بتشغيل الوظيفة deplace() بحيث يتحرك الطريق للأعلى إلى ما لا نهاية. ولكن إذا لم تقم بتنشيطه مرة واحدة ، فلن يحدث شيء على الشاشة. يجب عليك إدراج العبارة deplace(); قبل العلامة قليلاً </script> .
عرض وتحريك السيارة الحمراء
يجب أن تتحرك السيارة الحمراء من الأسفلالى الأعلى وأن تظهر بشكل عشوائي. هنا هو الرمز المستخدم:

function deplace()
{
  $('#vr').animate({top: '-=600'}, 2500, 'linear', function(){
    var vrX = Math.floor(Math.random()*194)+70;
    var vrY = 400;
    $('#vr').css('top',vrY);
    $('#vr').css('left',vrX);
  });
  // الدالة animate()
  // لتحريك العجلات
};
لا تخف من هذا الكود. لا يوجد شيء من السحر هناك!
التعليمة الأولى تنقل خطياً السيارة الحمراء إلى 600 بكسل في 2500 مللي ثانية. هذا هو نفس مبدأ تحريك الطريق ، إلا أنه هنا يمكنك تحريك السيارة بمقدار 600 بكسل للأعلى بحيث تختفي تمامًا من الشاشة. خذ الاختبار بقيمة أقل من 400 ، وسوف تفهم. كما أنه يغير وقت التمرير: فالصورة لديها المزيد من الطريق للتقدم ، لذلك يسمح باعطاء اللاعب الوقت لتجنب السيارة. عند انتهاء الحركة ، يجب عرض سيارة حمراء جديدة. لهذا ، نرسم بشكل عشوائي عددًا يتراوح بين 70 و 194 + 70 ، أو 264. يتم تخزين هذا الرقم في المتغيرvrX . يتوافق مع الإحداثيات (الإحداثيات الأفقية) للسيارة الحمراء عندما يتم عرضها لأول مرة. يجب أن تكون هذه الاحداثيات على الطريق. تم الحصول على القيمتين 70 و 264 باستخدام برنامج خاص بالرسومات.
jQuery web
الحد الأدنى والحد الأقصى لعرض السيارة الحمراء
تحريك السيارة الصفراء
السيارة الصفراء تتحرك أفقيا مع أزرار لوحة المفاتيح يسار و يمين. لذلك يكفي التقاط النقر على هذه المفاتيح وإجراء العلاج اللازم. لهذا ، سنطبق طريقة الحدث keydown() على المستند:

$(document).keydown(function(e){ 
مفاتيح يسارو يمين لها رمز ASCII 37 و 39. وهكذا فقط لاختبار قيمة e.which لمعرفة الزر الذي تم الضغط عليه . إذا كان هذا هو المفتاح يمين، وإذا لم تكن السيارة بعيدة جدًا عن اليمين ، فسيتم تحريكها بمقدار 30 بكسل بفضل خاصية CSS left :

if (e.which == 39)
{
  vjX = parseInt($('#vj').css('left'));
  if (vjX < 280)
    $('#vj').css('left', vjX+30);
}
إذا تم ضغط المفتاح يسار ، وإذا لم تكن السيارة بعيدة جدًا عن اليسار ، فسيتم تحريكه بمقدار 30 بكسل بفضل خاصية CSS left :

if (e.which == 37)
{
  vjX = parseInt($('#vj').css('left'));
  if (vjX > 70)
    $('#vj').css('left', vjX-30);
}
بسيطة وفعالة!

كشف الاصطدامات


كيف تعرف إذا اصطدمت السيارات؟ من خلال مقارنة إحداثيات كل منهما ببساطة. هنا هو الكود المستخدم:

function collision()
{
  vjX = parseInt($('#vj').css('left'));
  vrX = parseInt($('#vr').css('left'));
  vjY = 10;
  vrY = parseInt($('#vr').css('top'));
  if (((vrX > vjX) && (vrX < (vjX+66)) && (vrY > vjY) && (vrY < (vjY+150)) &&(ok == 1))
  || ((vjX > vrX) && (vjX < (vrX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)))
  {
    collision = parseInt($('#info').text()) + 1;
    $('#info').text(collision);
    ok = 0;
  }  
}
في الأسطر الأولى وضعت إحداثيات السيارة الصفراء في المتغيرات vjX و vjY وتلك السيارة الحمراء في المتغيرات vrX و vrY . تمثل الخطوط 7 و 8 اختبار التصادم. السطر الأول يتعامل مع الاصطدامات على الجانب الأيسر.
jQuery web
حدث تصادم على اليسار
تقارن إحداثيات السيارتين بافتراض أن السيارة الحمراء أكثر يمينًا من السيارة الصفراء في الملعب ، وإذا اصطدمت السيارة الحمراء من اليسار ، يتم فحص الاختبار والخطوط من 10 إلى 12 ثانية "على التوالي. بنفس الطريقة ، يقارن السطر الثاني إحداثيات السيارتين بافتراض أن السيارة الحمراء أكثر على اليسار من السيارة الصفراء في الملعب ، وإذا اصطدمت السيارة الحمراء على اليمين ، يتم فحص الاختبار. وخطوط 10 إلى 12 المدى.
ما هو المتغير ok في كل من اختبارات التصادم وإرشادات التعطل؟
بدون هذا المتغير ، في حالة حدوث تصادم ، سيتم اكتشاف العديد من التصادمات أثناء تحرك السيارة الحمراء للأعلى. لكي يقوم المتغير ok بأداء وظيفته ، يجب أن تقوم بتهيئته إلى 1 في بداية الرمز وفي نهاية حركة كل سيارة حمراء:

$(function() {
  var ok = 1;
  ... 
... و:

function deplace()
{
  $('#vr').animate({top: '-=600'}, 2500, 'linear', function(){
  var vrX = Math.floor(Math.random()*194)+70;
  var vrY = 400;
  $('#vr').css('top',vrY);
  $('#vr').css('left',vrX);
  ok = 1;
});
... 
عند حدوث تصادم ، يتم زيادة عدد التصادمات بمقدار 1 في العلامة <span id="info"> . لهذه المهمة التي يتعين القيام بها على فترات منتظمة (هنا، كل 20 ميلي ثانية)، ونحن نستخدم وظيفة setInterval() :

setInterval(collision, 20); 

إضافة الأصوات


ماذا عن إضافة تأثير الصوت إلى كل تصادم؟ هذا مرة أخرى بسيط للغاية ، بشرط أن تستخدم متصفحًا حديثًا ومتوافقًا مع HTML5 . ابدأ بإدراج علامة <audio> في المستند:

<audio preload="auto" id="son">
  <source src="beep.mp3" type="audio/mp3">
  <source src="beep.ogg" type="audio/ogg">
</audio>
كما ترون، نحن نستخدم اثنين من صيغ الصوت: MP3 و OGG . هذا لضمان توافق التعليمات البرمجية مع معظم المتصفحات في السوق. سيستخدم كل مستعرض نوع الملف الذي يمكنه قراءته. على سبيل المثال ، سيختار Internet Explorer ملف MP3 و Firefox و Google Chrome OGG .
ستجد بسهولة العديد من المؤثرات الخاصة على الويب ، لكن مرة أخرى أقترح عليك تنزيل التأثير الذي استخدمته لهذا الفصل.
لتشغيل الصوت ، استخدم عبارة jQuery التالية:

$('#son')[0].play();
إذا وضعت هذه التعليمات في الوظيفة collision() ، مباشرة بعد الإرشادات if التي تختبر حدوث تصادم ، فسيحدث تأثير الصوت في كل مرة تصطدم فيها السيارات:

if (((vrX > vjX) && (vrX < (vjX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)) 
|| ((vjX > vrX) && (vjX < (vrX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)))
{
  $('#son')[0].play();
  ... 

الكود الكامل


أقترح اختبار النتيجة النهائية من خلال النقر هنا . بالإضافة إلى ذلك ، إليك الرمز الكامل للتطبيق. ! النقر هنا بالإضافة إلى ذلك ، إليك الرمز الكامل للتطبيق. وقتا ممتعا

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jeu</title>
  <style type="text/css">
    #jeu{
      width: 400px;
      height: 400px;
      border: 2px black solid;
      overflow: hidden;
      position: relative;
    }
    .fond{
      margin-bottom:-5px; 
      z-index: 10;
      position: relative;
    }
    #vj{
      z-index: 100; 
      position: absolute; 
      top: 10px; 
      left: 48px;
    }
    #vr{
      z-index: 80; 
      position: absolute; 
      top: -200px; 
      left: 0px;
    }
  </style>
</head>

<body>
  Collisions : <span id="info">0</span>
  <div id="jeu">
    <img id="fond1" class="fond" src="route.png">
    <img id="fond2" class="fond" src="route.png">
    <img id="vj" src="vj.png">
    <img id="vr" src="vr.png">
  </div>
  <audio preload="auto" id="son"><source src="beep.mp3" type="audio/mp3"><source src="beep.ogg" type="audio/ogg"></audio>

  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
  <script>
    $(function() {
      var ok = 1;
      function deplace()
      {
        $('#vr').animate({top: '-=600'}, 2500, 'linear', function(){
          var vrX = Math.floor(Math.random()*194)+70;
          var vrY = 400;
          $('#vr').css('top',vrY);
          $('#vr').css('left',vrX);
          ok = 1;
        });
        $('.fond').animate({top: '-=360'}, 1000, 'linear', function(){
          $('.fond').css('top',0);
          deplace();
        });
      };
       
      $(document).keydown(function(e){
        if (e.which == 39)
        {
          vjX = parseInt($('#vj').css('left'));
          if (vjX < 280)
          $('#vj').css('left', vjX+30);
        }
        if (e.which == 37)
        {
          vjX = parseInt($('#vj').css('left'));
          if (vjX > 70)
            $('#vj').css('left', vjX-30);
        }
      });

      function collision()
      {
        vjX = parseInt($('#vj').css('left'));
        vrX = parseInt($('#vr').css('left'));
        vjY = 10;
        vrY = parseInt($('#vr').css('top'));
        if (((vrX > vjX) && (vrX < (vjX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)) 
        || ((vjX > vrX) && (vjX < (vrX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)))
        {
          $('#son')[0].play();
          collision = parseInt($('#info').text()) + 1;
          $('#info').text(collision);
      ok = 0;
        }
      }
      deplace();
      setInterval(collision, 20);
    });
  </script>
</body>
</html>