15 KiB
ساخت یک بازی فضایی قسمت ۴: اضافه کردن لیزر و تشخیص برخوردها
آزمون پیش از درس
در این درس یاد میگیرید که چگونه با استفاده از جاوااسکریپت لیزر شلیک کنید! ما دو ویژگی به بازی خود اضافه خواهیم کرد:
- یک لیزر: این لیزر از سفینه قهرمان شما شلیک شده و به صورت عمودی به سمت بالا حرکت میکند.
- تشخیص برخورد: به عنوان بخشی از قابلیت شلیک، قوانین جالبی به بازی اضافه میکنیم:
- برخورد لیزر با دشمن: اگر لیزر به دشمن برخورد کند، دشمن از بین میرود.
- برخورد لیزر با بالای صفحه: اگر لیزر به بالای صفحه برخورد کند، از بین میرود.
- برخورد دشمن با قهرمان: اگر دشمن و قهرمان به هم برخورد کنند، هر دو از بین میروند.
- برخورد دشمن با پایین صفحه: اگر دشمن به پایین صفحه برخورد کند، دشمن و قهرمان از بین میروند.
به طور خلاصه، شما -- قهرمان -- باید قبل از اینکه دشمنان به پایین صفحه برسند، همه آنها را با لیزر از بین ببرید.
✅ کمی تحقیق کنید درباره اولین بازی کامپیوتری که ساخته شده است. عملکرد آن چگونه بود؟
بیایید با هم قهرمان باشیم!
تشخیص برخورد
چگونه میتوانیم برخوردها را تشخیص دهیم؟ باید اشیای بازی خود را به عنوان مستطیلهایی که در حال حرکت هستند در نظر بگیریم. چرا؟ چون تصویری که برای رسم یک شیء بازی استفاده میشود، یک مستطیل است: این تصویر دارای x
، y
، عرض
و ارتفاع
است.
اگر دو مستطیل، یعنی قهرمان و دشمن، همپوشانی داشته باشند، یک برخورد رخ داده است. اینکه بعد از برخورد چه اتفاقی بیفتد، به قوانین بازی بستگی دارد. برای پیادهسازی تشخیص برخورد، به موارد زیر نیاز دارید:
-
روشی برای دریافت نمای مستطیلی از یک شیء بازی، چیزی شبیه به این:
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);
چگونه لیزر شلیک کنیم
شلیک لیزر به معنای پاسخ به یک رویداد کلید و ایجاد یک شیء است که در یک جهت خاص حرکت میکند. بنابراین باید مراحل زیر را انجام دهید:
- ایجاد یک شیء لیزر: از بالای سفینه قهرمان شما، که پس از ایجاد به سمت بالای صفحه حرکت میکند.
- اتصال کد به یک رویداد کلید: باید یک کلید روی صفحهکلید انتخاب کنیم که نمایانگر شلیک لیزر توسط بازیکن باشد.
- ایجاد یک شیء بازی که شبیه لیزر باشد وقتی کلید فشار داده میشود.
زمانبندی شلیک لیزر
لیزر باید هر بار که کلید خاصی، مثلاً space، فشار داده میشود شلیک شود. برای جلوگیری از تولید تعداد زیادی لیزر در مدت زمان کوتاه، باید این مشکل را حل کنیم. راهحل این است که یک زمانبندی پیادهسازی کنیم که اطمینان دهد لیزر فقط در بازههای زمانی مشخصی شلیک میشود. میتوانید این کار را به این صورت انجام دهید:
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 ); }
-
اضافه کردن قابلیت شلیک لیزر
-
اضافه کردن پیام رویداد کلید. کلید space باید یک لیزر درست بالای سفینه قهرمان ایجاد کند. سه ثابت به شیء Messages اضافه کنید:
KEY_EVENT_SPACE: "KEY_EVENT_SPACE", COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER", COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
-
مدیریت کلید space. تابع
window.addEventListener
مربوط به رویداد keyup را ویرایش کنید تا کلید space را مدیریت کند:} else if(evt.keyCode === 32) { eventEmitter.emit(Messages.KEY_EVENT_SPACE); }
-
اضافه کردن شنوندهها. تابع
initGame()
را ویرایش کنید تا اطمینان حاصل شود که قهرمان میتواند هنگام فشار دادن کلید space شلیک کند: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; } }
-
در این مرحله، بازی شما دارای برخی قابلیتها است! میتوانید با کلیدهای جهتدار حرکت کنید، با کلید space لیزر شلیک کنید، و دشمنان وقتی به آنها برخورد میکنید ناپدید میشوند. آفرین!
🚀 چالش
یک انفجار اضافه کنید! به داراییهای بازی در مخزن Space Art نگاهی بیندازید و سعی کنید هنگام برخورد لیزر با یک بیگانه، یک انفجار اضافه کنید.
آزمون پس از درس
مرور و مطالعه شخصی
با بازههای زمانی در بازی خود تا اینجا آزمایش کنید. وقتی آنها را تغییر میدهید چه اتفاقی میافتد؟ درباره رویدادهای زمانبندی جاوااسکریپت بیشتر بخوانید.
تکلیف
سلب مسئولیت:
این سند با استفاده از سرویس ترجمه هوش مصنوعی Co-op Translator ترجمه شده است. در حالی که ما تلاش میکنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمههای خودکار ممکن است شامل خطاها یا نادرستیها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، توصیه میشود از ترجمه حرفهای انسانی استفاده کنید. ما مسئولیتی در قبال سوء تفاهمها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.