You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ar/6-space-game/4-collision-detection
softchris 04881ec984
🌐 Update translations via Co-op Translator
2 months ago
..
solution 🌐 Update translations via Co-op Translator 3 months ago
your-work 🌐 Update translations via Co-op Translator 3 months ago
README.md 🌐 Update translations via Co-op Translator 2 months ago
assignment.md 🌐 Update translations via Co-op Translator 3 months ago

README.md

بناء لعبة فضاء الجزء الرابع: إضافة الليزر واكتشاف التصادمات

اختبار ما قبل المحاضرة

اختبار ما قبل المحاضرة

في هذه الدرس ستتعلم كيفية إطلاق الليزر باستخدام JavaScript! سنضيف عنصرين إلى لعبتنا:

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

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

قم بإجراء بحث صغير عن أول لعبة كمبيوتر تم كتابتها على الإطلاق. ما هي وظيفتها؟

لنكن أبطالًا معًا!

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

كيف نقوم باكتشاف التصادمات؟ نحتاج إلى التفكير في كائنات اللعبة كأنها مستطيلات تتحرك. لماذا؟ لأن الصورة المستخدمة لرسم كائن اللعبة هي مستطيل: يحتوي على x، y، width و height.

إذا تقاطع مستطيلان، أي البطل والعدو، يحدث تصادم. ما يجب أن يحدث بعد ذلك يعتمد على قواعد اللعبة. لتنفيذ اكتشاف التصادمات تحتاج إلى ما يلي:

  1. طريقة للحصول على تمثيل مستطيل لكائن اللعبة، شيء مثل هذا:

    rectFromGameObject() {
      return {
        top: this.y,
        left: this.x,
        bottom: this.y + this.height,
        right: this.x + this.width
      }
    }
    
  2. وظيفة مقارنة، يمكن أن تبدو هذه الوظيفة كالتالي:

    function intersectRect(r1, r2) {
      return !(r2.left > r1.right ||
        r2.right < r1.left ||
        r2.top > r1.bottom ||
        r2.bottom < r1.top);
    }
    

كيف ندمر الأشياء

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

// collision happened
enemy.dead = true

ثم يمكنك متابعة فرز الكائنات الميتة قبل إعادة رسم الشاشة، مثل هذا:

gameObjects = gameObject.filter(go => !go.dead);

كيف نطلق الليزر

إطلاق الليزر يعني الاستجابة لحدث مفتاح وإنشاء كائن يتحرك في اتجاه معين. لذلك نحتاج إلى تنفيذ الخطوات التالية:

  1. إنشاء كائن ليزر: من أعلى سفينة البطل، يبدأ بالتحرك نحو الأعلى باتجاه أعلى الشاشة عند إنشائه.
  2. إرفاق كود لحدث مفتاح: نحتاج إلى اختيار مفتاح على لوحة المفاتيح يمثل إطلاق اللاعب لليزر.
  3. إنشاء كائن لعبة يبدو كأنه ليزر عند الضغط على المفتاح.

فترة التهدئة لليزر

يحتاج الليزر إلى الإطلاق في كل مرة تضغط فيها على مفتاح، مثل المسافة على سبيل المثال. لمنع اللعبة من إنتاج عدد كبير جدًا من الليزرات في وقت قصير، نحتاج إلى إصلاح ذلك. يتم الإصلاح عن طريق تنفيذ ما يسمى بـ فترة التهدئة، وهي مؤقت يضمن أن الليزر يمكن إطلاقه فقط في فترات محددة. يمكنك تنفيذ ذلك بالطريقة التالية:

class Cooldown {
  constructor(time) {
    this.cool = false;
    setTimeout(() => {
      this.cool = true;
    }, time)
  }
}

class Weapon {
  constructor {
  }
  fire() {
    if (!this.cooldown || this.cooldown.cool) {
      // produce a laser
      this.cooldown = new Cooldown(500);
    } else {
      // do nothing - it hasn't cooled down yet.
    }
  }
}

ارجع إلى الدرس الأول في سلسلة لعبة الفضاء لتذكير نفسك بـ فترات التهدئة.

ما الذي سنبنيه

ستأخذ الكود الموجود (الذي يجب أن تكون قد نظفته وأعدت ترتيبه) من الدرس السابق، وتقوم بتوسيعه. إما أن تبدأ بالكود من الجزء الثاني أو تستخدم الكود في الجزء الثالث - البداية.

نصيحة: الليزر الذي ستعمل عليه موجود بالفعل في مجلد الأصول الخاص بك ومشار إليه بواسطة الكود الخاص بك.

  • أضف اكتشاف التصادمات، عندما يصطدم الليزر بشيء يجب أن تنطبق القواعد التالية:
    1. الليزر يصيب العدو: يموت العدو إذا أصيب بالليزر.
    2. الليزر يصيب أعلى الشاشة: يتم تدمير الليزر إذا أصاب الجزء العلوي من شاشتنا.
    3. تصادم العدو والبطل: يتم تدمير العدو والبطل إذا اصطدموا ببعضهم البعض.
    4. العدو يصيب أسفل الشاشة: يتم تدمير العدو والبطل إذا وصل العدو إلى أسفل الشاشة.

الخطوات الموصى بها

حدد الملفات التي تم إنشاؤها لك في مجلد your-work. يجب أن تحتوي على ما يلي:

-| assets
  -| enemyShip.png
  -| player.png
  -| laserRed.png
-| index.html
-| app.js
-| package.json

ابدأ مشروعك في مجلد your_work عن طريق كتابة:

cd your-work
npm start

سيقوم الأمر أعلاه بتشغيل خادم HTTP على العنوان http://localhost:5000. افتح متصفحًا وأدخل هذا العنوان، في الوقت الحالي يجب أن يعرض البطل وجميع الأعداء، لا شيء يتحرك - حتى الآن :).

إضافة الكود

  1. إعداد تمثيل مستطيل لكائن اللعبة للتعامل مع التصادم الكود أدناه يسمح لك بالحصول على تمثيل مستطيل لـ GameObject. قم بتحرير فئة GameObject لتوسيعها:

    rectFromGameObject() {
        return {
          top: this.y,
          left: this.x,
          bottom: this.y + this.height,
          right: this.x + this.width,
        };
      }
    
  2. إضافة كود يتحقق من التصادم ستكون هذه وظيفة جديدة تختبر ما إذا كانت مستطيلان يتقاطعان:

    function intersectRect(r1, r2) {
      return !(
        r2.left > r1.right ||
        r2.right < r1.left ||
        r2.top > r1.bottom ||
        r2.bottom < r1.top
      );
    }
    
  3. إضافة قدرة إطلاق الليزر

    1. إضافة رسالة حدث المفتاح. يجب أن يقوم مفتاح المسافة بإنشاء ليزر فوق سفينة البطل. أضف ثلاث ثوابت في كائن Messages:

       KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
       COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
       COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
      
    2. التعامل مع مفتاح المسافة. قم بتحرير وظيفة window.addEventListener الخاصة بـ keyup للتعامل مع المسافة:

        } else if(evt.keyCode === 32) {
          eventEmitter.emit(Messages.KEY_EVENT_SPACE);
        }
      
    3. إضافة مستمعين. قم بتحرير وظيفة initGame() لضمان أن البطل يمكنه الإطلاق عند الضغط على مفتاح المسافة:

      eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
       if (hero.canFire()) {
         hero.fire();
       }
      

      وأضف وظيفة جديدة eventEmitter.on() لضمان السلوك عند اصطدام العدو بالليزر:

      eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
        first.dead = true;
        second.dead = true;
      })
      
    4. تحريك الكائن، تأكد من أن الليزر يتحرك تدريجيًا إلى أعلى الشاشة. ستقوم بإنشاء فئة جديدة Laser تمتد من GameObject، كما فعلت من قبل:

        class Laser extends GameObject {
        constructor(x, y) {
          super(x,y);
          (this.width = 9), (this.height = 33);
          this.type = 'Laser';
          this.img = laserImg;
          let id = setInterval(() => {
            if (this.y > 0) {
              this.y -= 15;
            } else {
              this.dead = true;
              clearInterval(id);
            }
          }, 100)
        }
      }
      
    5. التعامل مع التصادمات، قم بتنفيذ قواعد التصادم لليزر. أضف وظيفة updateGameObjects() التي تختبر الكائنات المتصادمة للإصابات:

      function updateGameObjects() {
        const enemies = gameObjects.filter(go => go.type === 'Enemy');
        const lasers = gameObjects.filter((go) => go.type === "Laser");
      // laser hit something
        lasers.forEach((l) => {
          enemies.forEach((m) => {
            if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) {
            eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
              first: l,
              second: m,
            });
          }
         });
      });
      
        gameObjects = gameObjects.filter(go => !go.dead);
      }  
      

      تأكد من إضافة updateGameObjects() إلى حلقة اللعبة في window.onload.

    6. تنفيذ فترة التهدئة لليزر، بحيث يمكن إطلاقه فقط في فترات محددة.

      أخيرًا، قم بتحرير فئة Hero بحيث يمكنها التهدئة:

      class Hero extends GameObject {
       constructor(x, y) {
         super(x, y);
         (this.width = 99), (this.height = 75);
         this.type = "Hero";
         this.speed = { x: 0, y: 0 };
         this.cooldown = 0;
       }
       fire() {
         gameObjects.push(new Laser(this.x + 45, this.y - 10));
         this.cooldown = 500;
      
         let id = setInterval(() => {
           if (this.cooldown > 0) {
             this.cooldown -= 100;
           } else {
             clearInterval(id);
           }
         }, 200);
       }
       canFire() {
         return this.cooldown === 0;
       }
      }
      

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

تحدي GitHub Copilot Agent 🚀

استخدم وضع Agent لإكمال التحدي التالي:

الوصف: قم بتحسين نظام اكتشاف التصادمات عن طريق تنفيذ عناصر تعزيز تظهر بشكل عشوائي وتوفر قدرات مؤقتة عند جمعها بواسطة سفينة البطل.

المهمة: قم بإنشاء فئة PowerUp تمتد من GameObject وتنفيذ اكتشاف التصادم بين البطل وعناصر التعزيز. أضف نوعين على الأقل من عناصر التعزيز: واحد يزيد معدل الإطلاق (يقلل فترة التهدئة) وآخر ينشئ درعًا مؤقتًا. قم بتضمين منطق الظهور الذي ينشئ عناصر التعزيز في فترات ومواقع عشوائية.


🚀 التحدي

أضف انفجارًا! ألقِ نظرة على أصول اللعبة في مستودع فن الفضاء وحاول إضافة انفجار عندما يصيب الليزر كائنًا فضائيًا.

اختبار ما بعد المحاضرة

اختبار ما بعد المحاضرة

المراجعة والدراسة الذاتية

جرب تغيير الفواصل الزمنية في لعبتك حتى الآن. ماذا يحدث عندما تغيرها؟ اقرأ المزيد عن أحداث توقيت JavaScript.

الواجب

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


إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.