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/fa/6-space-game/4-collision-detection
Lee Stott 2daab5271b
Update Quiz Link
3 weeks ago
..
solution 🌐 Update translations via Co-op Translator 4 weeks ago
your-work 🌐 Update translations via Co-op Translator 4 weeks ago
README.md Update Quiz Link 3 weeks ago
assignment.md 🌐 Update translations via Co-op Translator 4 weeks ago

README.md

ساخت یک بازی فضایی قسمت ۴: اضافه کردن لیزر و تشخیص برخوردها

آزمون پیش از درس

آزمون پیش از درس

در این درس یاد می‌گیرید که چگونه با استفاده از جاوااسکریپت لیزر شلیک کنید! ما دو ویژگی به بازی خود اضافه خواهیم کرد:

  • لیزر: این لیزر از سفینه قهرمان شما شلیک شده و به صورت عمودی به سمت بالا حرکت می‌کند.
  • تشخیص برخورد: به عنوان بخشی از قابلیت شلیک، قوانین جذابی به بازی اضافه می‌کنیم:
    • برخورد لیزر با دشمن: دشمن در صورت برخورد با لیزر نابود می‌شود.
    • برخورد لیزر با بالای صفحه: لیزر در صورت برخورد با بالای صفحه نابود می‌شود.
    • برخورد دشمن و قهرمان: دشمن و قهرمان در صورت برخورد با یکدیگر نابود می‌شوند.
    • برخورد دشمن با پایین صفحه: دشمن و قهرمان در صورت رسیدن دشمن به پایین صفحه نابود می‌شوند.

به طور خلاصه، شما -- قهرمان -- باید تمام دشمنان را با لیزر نابود کنید قبل از اینکه به پایین صفحه برسند.

کمی تحقیق کنید درباره اولین بازی کامپیوتری که تاکنون نوشته شده است. عملکرد آن چگونه بود؟

بیایید با هم قهرمان باشیم!

تشخیص برخورد

چگونه می‌توانیم برخوردها را تشخیص دهیم؟ باید اشیاء بازی خود را به عنوان مستطیل‌هایی که حرکت می‌کنند در نظر بگیریم. چرا؟ چون تصویری که برای نمایش یک شیء بازی استفاده می‌شود یک مستطیل است: این تصویر دارای x، y، عرض و ارتفاع است.

اگر دو مستطیل، یعنی قهرمان و دشمن، همپوشانی داشته باشند، برخورد رخ داده است. اینکه چه اتفاقی باید بیفتد به قوانین بازی بستگی دارد. برای پیاده‌سازی تشخیص برخورد، به موارد زیر نیاز دارید:

  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. ایجاد یک شیء بازی که شبیه لیزر باشد وقتی کلید فشار داده می‌شود.

زمان‌بندی شلیک لیزر

لیزر باید هر بار که کلید فشار داده می‌شود، مانند 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.
    }
  }
}

به درس ۱ در سری بازی فضایی مراجعه کنید تا درباره زمان‌بندی یادآوری کنید.

چه چیزی بسازیم

شما باید کد موجود (که باید آن را پاک‌سازی و بازسازی کرده باشید) از درس قبلی را گسترش دهید. یا با کد قسمت دوم شروع کنید یا از کد قسمت سوم - شروع‌کننده استفاده کنید.

نکته: لیزری که با آن کار خواهید کرد، قبلاً در پوشه دارایی‌های شما قرار دارد و توسط کد شما ارجاع داده شده است.

  • تشخیص برخورد اضافه کنید، وقتی لیزر با چیزی برخورد می‌کند، قوانین زیر باید اعمال شوند:
    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. اضافه کردن پیام رویداد کلید. کلید space باید یک لیزر درست بالای سفینه قهرمان ایجاد کند. سه ثابت در شیء Messages اضافه کنید:

       KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
       COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
       COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
      
    2. مدیریت کلید space. تابع window.addEventListener مربوط به رویداد keyup را ویرایش کنید تا کلید space را مدیریت کند:

        } else if(evt.keyCode === 32) {
          eventEmitter.emit(Messages.KEY_EVENT_SPACE);
        }
      
    3. اضافه کردن شنونده‌ها. تابع 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;
      })
      
    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;
       }
      }
      

در این مرحله، بازی شما دارای برخی قابلیت‌ها است! می‌توانید با کلیدهای جهت‌دار حرکت کنید، با کلید space لیزر شلیک کنید، و دشمنان هنگام برخورد با لیزر ناپدید می‌شوند. آفرین!


🚀 چالش

یک انفجار اضافه کنید! به دارایی‌های بازی در مخزن هنر فضایی نگاهی بیندازید و سعی کنید هنگام برخورد لیزر با یک بیگانه، یک انفجار اضافه کنید.

آزمون پس از درس

آزمون پس از درس

مرور و مطالعه شخصی

با بازه‌های زمانی در بازی خود تا اینجا آزمایش کنید. وقتی آنها را تغییر می‌دهید چه اتفاقی می‌افتد؟ درباره رویدادهای زمان‌بندی جاوااسکریپت بیشتر بخوانید.

تکلیف

بررسی برخوردها

سلب مسئولیت:
این سند با استفاده از سرویس ترجمه هوش مصنوعی Co-op Translator ترجمه شده است. در حالی که ما تلاش می‌کنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمه‌های خودکار ممکن است شامل خطاها یا نادرستی‌ها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حیاتی، ترجمه حرفه‌ای انسانی توصیه می‌شود. ما مسئولیتی در قبال سوء تفاهم‌ها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.