# ساخت یک بازی فضایی قسمت ۴: اضافه کردن لیزر و تشخیص برخوردها ## آزمون پیش از درس [آزمون پیش از درس](https://ff-quizzes.netlify.app/web/quiz/35) در این درس یاد می‌گیرید که چگونه با استفاده از جاوااسکریپت لیزر شلیک کنید! ما دو ویژگی به بازی خود اضافه خواهیم کرد: - **لیزر**: این لیزر از سفینه قهرمان شما شلیک شده و به صورت عمودی به سمت بالا حرکت می‌کند. - **تشخیص برخورد**: به عنوان بخشی از قابلیت شلیک، قوانین جذابی به بازی اضافه می‌کنیم: - **برخورد لیزر با دشمن**: دشمن در صورت برخورد با لیزر نابود می‌شود. - **برخورد لیزر با بالای صفحه**: لیزر در صورت برخورد با بالای صفحه نابود می‌شود. - **برخورد دشمن و قهرمان**: دشمن و قهرمان در صورت برخورد با یکدیگر نابود می‌شوند. - **برخورد دشمن با پایین صفحه**: دشمن و قهرمان در صورت رسیدن دشمن به پایین صفحه نابود می‌شوند. به طور خلاصه، شما -- *قهرمان* -- باید تمام دشمنان را با لیزر نابود کنید قبل از اینکه به پایین صفحه برسند. ✅ کمی تحقیق کنید درباره اولین بازی کامپیوتری که تاکنون نوشته شده است. عملکرد آن چگونه بود؟ بیایید با هم قهرمان باشیم! ## تشخیص برخورد چگونه می‌توانیم برخوردها را تشخیص دهیم؟ باید اشیاء بازی خود را به عنوان مستطیل‌هایی که حرکت می‌کنند در نظر بگیریم. چرا؟ چون تصویری که برای نمایش یک شیء بازی استفاده می‌شود یک مستطیل است: این تصویر دارای `x`، `y`، `عرض` و `ارتفاع` است. اگر دو مستطیل، یعنی قهرمان و دشمن، *همپوشانی* داشته باشند، برخورد رخ داده است. اینکه چه اتفاقی باید بیفتد به قوانین بازی بستگی دارد. برای پیاده‌سازی تشخیص برخورد، به موارد زیر نیاز دارید: 1. روشی برای دریافت نمای مستطیلی از یک شیء بازی، چیزی شبیه به این: ```javascript rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width } } ``` 2. یک تابع مقایسه، این تابع می‌تواند به این شکل باشد: ```javascript function intersectRect(r1, r2) { return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); } ``` ## چگونه اشیاء را نابود کنیم برای نابود کردن اشیاء در بازی، باید به بازی اطلاع دهید که دیگر نباید این آیتم را در حلقه بازی که در یک بازه زمانی مشخص اجرا می‌شود، نمایش دهد. یک روش برای این کار این است که یک شیء بازی را در صورت وقوع یک اتفاق به عنوان *مرده* علامت‌گذاری کنید، به این صورت: ```javascript // collision happened enemy.dead = true ``` سپس می‌توانید اشیاء *مرده* را قبل از بازپخش صفحه مرتب کنید، به این صورت: ```javascript gameObjects = gameObject.filter(go => !go.dead); ``` ## چگونه لیزر شلیک کنیم شلیک لیزر به معنای پاسخ به یک رویداد کلید و ایجاد یک شیء است که در یک جهت خاص حرکت می‌کند. بنابراین باید مراحل زیر را انجام دهید: 1. **ایجاد یک شیء لیزر**: از بالای سفینه قهرمان شما، که پس از ایجاد شروع به حرکت به سمت بالای صفحه می‌کند. 2. **اتصال کد به یک رویداد کلید**: باید یک کلید روی صفحه‌کلید انتخاب کنیم که نمایانگر شلیک لیزر توسط بازیکن باشد. 3. **ایجاد یک شیء بازی که شبیه لیزر باشد** وقتی کلید فشار داده می‌شود. ## زمان‌بندی شلیک لیزر لیزر باید هر بار که کلید فشار داده می‌شود، مانند *space*، شلیک شود. برای جلوگیری از تولید تعداد زیادی لیزر در مدت زمان کوتاه، باید این مشکل را حل کنیم. راه‌حل این مشکل پیاده‌سازی چیزی به نام *زمان‌بندی* است، یک تایمر که اطمینان حاصل می‌کند لیزر فقط در بازه‌های زمانی مشخصی شلیک شود. می‌توانید این کار را به این صورت انجام دهید: ```javascript 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) استفاده کنید. > نکته: لیزری که با آن کار خواهید کرد، قبلاً در پوشه دارایی‌های شما قرار دارد و توسط کد شما ارجاع داده شده است. - **تشخیص برخورد اضافه کنید**، وقتی لیزر با چیزی برخورد می‌کند، قوانین زیر باید اعمال شوند: 1. **برخورد لیزر با دشمن**: دشمن در صورت برخورد با لیزر نابود می‌شود. 2. **برخورد لیزر با بالای صفحه**: لیزر در صورت برخورد با بالای صفحه نابود می‌شود. 3. **برخورد دشمن و قهرمان**: دشمن و قهرمان در صورت برخورد با یکدیگر نابود می‌شوند. 4. **برخورد دشمن با پایین صفحه**: دشمن و قهرمان در صورت رسیدن دشمن به پایین صفحه نابود می‌شوند. ## مراحل پیشنهادی فایل‌هایی که برای شما ایجاد شده‌اند را در پوشه `your-work` پیدا کنید. این پوشه باید شامل موارد زیر باشد: ```bash -| assets -| enemyShip.png -| player.png -| laserRed.png -| index.html -| app.js -| package.json ``` پروژه خود را در پوشه `your_work` با تایپ کردن دستور زیر شروع کنید: ```bash cd your-work npm start ``` دستور بالا یک سرور HTTP را در آدرس `http://localhost:5000` راه‌اندازی می‌کند. یک مرورگر باز کنید و این آدرس را وارد کنید، در حال حاضر باید قهرمان و تمام دشمنان را نمایش دهد، اما هنوز هیچ چیزی حرکت نمی‌کند :). ### اضافه کردن کد 1. **ایجاد نمای مستطیلی برای شیء بازی برای مدیریت برخورد** کد زیر به شما اجازه می‌دهد نمای مستطیلی از یک `GameObject` دریافت کنید. کلاس GameObject خود را ویرایش کنید تا آن را گسترش دهید: ```javascript rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width, }; } ``` 2. **اضافه کردن کدی که برخورد را بررسی کند** این یک تابع جدید خواهد بود که بررسی می‌کند آیا دو مستطیل همپوشانی دارند یا خیر: ```javascript function intersectRect(r1, r2) { return !( r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top ); } ``` 3. **اضافه کردن قابلیت شلیک لیزر** 1. **اضافه کردن پیام رویداد کلید**. کلید *space* باید یک لیزر درست بالای سفینه قهرمان ایجاد کند. سه ثابت در شیء Messages اضافه کنید: ```javascript KEY_EVENT_SPACE: "KEY_EVENT_SPACE", COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER", COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO", ``` 1. **مدیریت کلید space**. تابع `window.addEventListener` مربوط به رویداد keyup را ویرایش کنید تا کلید space را مدیریت کند: ```javascript } else if(evt.keyCode === 32) { eventEmitter.emit(Messages.KEY_EVENT_SPACE); } ``` 1. **اضافه کردن شنونده‌ها**. تابع `initGame()` را ویرایش کنید تا اطمینان حاصل شود که قهرمان می‌تواند هنگام فشار دادن کلید space شلیک کند: ```javascript eventEmitter.on(Messages.KEY_EVENT_SPACE, () => { if (hero.canFire()) { hero.fire(); } ``` و یک تابع جدید `eventEmitter.on()` اضافه کنید تا رفتار هنگام برخورد دشمن با لیزر را مدیریت کند: ```javascript eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => { first.dead = true; second.dead = true; }) ``` 1. **حرکت دادن شیء**، اطمینان حاصل کنید که لیزر به تدریج به بالای صفحه حرکت می‌کند. یک کلاس جدید Laser ایجاد کنید که از `GameObject` گسترش می‌یابد، همانطور که قبلاً انجام داده‌اید: ```javascript 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) } } ``` 1. **مدیریت برخوردها**، قوانین برخورد برای لیزر را پیاده‌سازی کنید. یک تابع `updateGameObjects()` اضافه کنید که اشیاء برخوردی را برای ضربه‌ها بررسی کند: ```javascript 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` اضافه کنید. 4. **پیاده‌سازی زمان‌بندی** برای لیزر، به طوری که فقط در بازه‌های زمانی مشخصی شلیک شود. در نهایت، کلاس Hero را ویرایش کنید تا بتواند زمان‌بندی داشته باشد: ```javascript 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; } } ``` در این مرحله، بازی شما دارای برخی قابلیت‌ها است! می‌توانید با کلیدهای جهت‌دار حرکت کنید، با کلید space لیزر شلیک کنید، و دشمنان هنگام برخورد با لیزر ناپدید می‌شوند. آفرین! --- ## 🚀 چالش یک انفجار اضافه کنید! به دارایی‌های بازی در [مخزن هنر فضایی](../../../../6-space-game/solution/spaceArt/readme.txt) نگاهی بیندازید و سعی کنید هنگام برخورد لیزر با یک بیگانه، یک انفجار اضافه کنید. ## آزمون پس از درس [آزمون پس از درس](https://ff-quizzes.netlify.app/web/quiz/36) ## مرور و مطالعه شخصی با بازه‌های زمانی در بازی خود تا اینجا آزمایش کنید. وقتی آنها را تغییر می‌دهید چه اتفاقی می‌افتد؟ درباره [رویدادهای زمان‌بندی جاوااسکریپت](https://www.freecodecamp.org/news/javascript-timing-events-settimeout-and-setinterval/) بیشتر بخوانید. ## تکلیف [بررسی برخوردها](assignment.md) **سلب مسئولیت**: این سند با استفاده از سرویس ترجمه هوش مصنوعی [Co-op Translator](https://github.com/Azure/co-op-translator) ترجمه شده است. در حالی که ما تلاش می‌کنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمه‌های خودکار ممکن است شامل خطاها یا نادرستی‌ها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حیاتی، ترجمه حرفه‌ای انسانی توصیه می‌شود. ما مسئولیتی در قبال سوء تفاهم‌ها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.