|
1 week ago | |
---|---|---|
.. | ||
solution | 2 weeks ago | |
your-work | 2 weeks ago | |
README.md | 1 week ago | |
assignment.md | 2 weeks ago |
README.md
بناء لعبة فضاء الجزء الرابع: إضافة الليزر واكتشاف التصادمات
اختبار ما قبل المحاضرة
في هذه الدرس ستتعلم كيفية إطلاق الليزر باستخدام JavaScript! سنضيف عنصرين إلى لعبتنا:
- الليزر: يتم إطلاق هذا الليزر من سفينة البطل عموديًا نحو الأعلى.
- اكتشاف التصادمات، كجزء من تنفيذ القدرة على الإطلاق، سنضيف بعض قواعد اللعبة الممتعة:
- الليزر يصيب العدو: يموت العدو إذا أصيب بالليزر.
- الليزر يصيب أعلى الشاشة: يتم تدمير الليزر إذا أصاب الجزء العلوي من الشاشة.
- تصادم العدو والبطل: يتم تدمير العدو والبطل إذا اصطدموا ببعضهم البعض.
- العدو يصيب أسفل الشاشة: يتم تدمير العدو والبطل إذا وصل العدو إلى أسفل الشاشة.
باختصار، أنت -- البطل -- تحتاج إلى إصابة جميع الأعداء بالليزر قبل أن يتمكنوا من الوصول إلى أسفل الشاشة.
✅ قم بإجراء بحث صغير حول أول لعبة كمبيوتر تم كتابتها على الإطلاق. ما هي وظيفتها؟
لنكن أبطالًا معًا!
اكتشاف التصادمات
كيف نقوم باكتشاف التصادمات؟ نحتاج إلى التفكير في كائنات اللعبة كأنها مستطيلات تتحرك. لماذا؟ لأن الصورة المستخدمة لرسم كائن اللعبة هي مستطيل: يحتوي على x
، y
، width
و height
.
إذا تقاطع مستطيلان، مثل البطل والعدو، يحدث تصادم. ما يجب أن يحدث بعد ذلك يعتمد على قواعد اللعبة. لتنفيذ اكتشاف التصادمات تحتاج إلى ما يلي:
-
طريقة للحصول على تمثيل مستطيل لكائن اللعبة، شيء مثل هذا:
rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width } }
-
وظيفة مقارنة، يمكن أن تبدو هذه الوظيفة كما يلي:
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);
كيف نطلق الليزر
إطلاق الليزر يعني الاستجابة لحدث مفتاح وإنشاء كائن يتحرك في اتجاه معين. لذلك نحتاج إلى تنفيذ الخطوات التالية:
- إنشاء كائن ليزر: من أعلى سفينة البطل، يبدأ بالتحرك نحو الأعلى باتجاه أعلى الشاشة عند إنشائه.
- إرفاق كود لحدث مفتاح: نحتاج إلى اختيار مفتاح على لوحة المفاتيح يمثل إطلاق اللاعب لليزر.
- إنشاء كائن لعبة يبدو كأنه ليزر عند الضغط على المفتاح.
فترة التهدئة لليزر
يحتاج الليزر إلى الإطلاق في كل مرة تضغط فيها على مفتاح، مثل المسافة على سبيل المثال. لمنع اللعبة من إنتاج عدد كبير جدًا من الليزرات في وقت قصير، نحتاج إلى إصلاح ذلك. يتم الإصلاح عن طريق تنفيذ ما يسمى بـ فترة التهدئة، وهي مؤقت يضمن أن الليزر يمكن إطلاقه فقط في فترات محددة. يمكنك تنفيذ ذلك بالطريقة التالية:
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.
}
}
}
✅ ارجع إلى الدرس الأول في سلسلة لعبة الفضاء لتذكير نفسك بـ فترات التهدئة.
ما الذي سنبنيه
ستأخذ الكود الموجود (الذي يجب أن تكون قد نظفته وأعدت ترتيبه) من الدرس السابق، وتقوم بتوسيعه. إما أن تبدأ بالكود من الجزء الثاني أو تستخدم الكود في الجزء الثالث - البداية.
نصيحة: الليزر الذي ستعمل عليه موجود بالفعل في مجلد الأصول الخاص بك ومشار إليه في الكود الخاص بك.
- إضافة اكتشاف التصادمات، عندما يصطدم الليزر بشيء ما، يجب تطبيق القواعد التالية:
- الليزر يصيب العدو: يموت العدو إذا أصيب بالليزر.
- الليزر يصيب أعلى الشاشة: يتم تدمير الليزر إذا أصاب الجزء العلوي من الشاشة.
- تصادم العدو والبطل: يتم تدمير العدو والبطل إذا اصطدموا ببعضهم البعض.
- العدو يصيب أسفل الشاشة: يتم تدمير العدو والبطل إذا وصل العدو إلى أسفل الشاشة.
الخطوات الموصى بها
حدد الملفات التي تم إنشاؤها لك في مجلد 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
. افتح متصفحًا وأدخل هذا العنوان، في الوقت الحالي يجب أن يعرض البطل وجميع الأعداء، ولكن لا شيء يتحرك - حتى الآن :).
إضافة الكود
-
إعداد تمثيل مستطيل لكائن اللعبة للتعامل مع التصادمات الكود أدناه يسمح لك بالحصول على تمثيل مستطيل لـ
GameObject
. قم بتعديل فئة GameObject لتوسيعها:rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width, }; }
-
إضافة كود يتحقق من التصادمات ستكون هذه وظيفة جديدة تختبر ما إذا كان مستطيلان يتقاطعان:
function intersectRect(r1, r2) { return !( r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top ); }
-
إضافة قدرة إطلاق الليزر
-
إضافة رسالة حدث المفتاح. يجب أن يقوم مفتاح المسافة بإنشاء ليزر فوق سفينة البطل. أضف ثلاث ثوابت في كائن Messages:
KEY_EVENT_SPACE: "KEY_EVENT_SPACE", COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER", COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
-
التعامل مع مفتاح المسافة. قم بتعديل وظيفة
window.addEventListener
الخاصة بـ keyup للتعامل مع المسافة:} else if(evt.keyCode === 32) { eventEmitter.emit(Messages.KEY_EVENT_SPACE); }
-
إضافة مستمعين. قم بتعديل وظيفة
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; })
-
تحريك الكائن، تأكد من أن الليزر يتحرك تدريجيًا إلى أعلى الشاشة. ستقوم بإنشاء فئة جديدة 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) } }
-
التعامل مع التصادمات، قم بتنفيذ قواعد التصادم لليزر. أضف وظيفة
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
. -
تنفيذ فترة التهدئة لليزر، بحيث يمكن إطلاقه فقط في فترات محددة.
أخيرًا، قم بتعديل فئة 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; } }
-
في هذه المرحلة، أصبحت لعبتك تحتوي على بعض الوظائف! يمكنك التنقل باستخدام مفاتيح الأسهم، إطلاق الليزر باستخدام مفتاح المسافة، واختفاء الأعداء عند إصابتهم. أحسنت!
🚀 التحدي
أضف انفجارًا! ألقِ نظرة على أصول اللعبة في مستودع فن الفضاء وحاول إضافة انفجار عندما يصيب الليزر كائنًا فضائيًا.
اختبار ما بعد المحاضرة
المراجعة والدراسة الذاتية
جرب تعديل الفواصل الزمنية في لعبتك حتى الآن. ماذا يحدث عندما تغيرها؟ اقرأ المزيد عن أحداث توقيت JavaScript.
الواجب
إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو معلومات غير دقيقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالاستعانة بترجمة بشرية احترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة ناتجة عن استخدام هذه الترجمة.