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/sr/6-space-game/4-collision-detection/README.md

16 KiB

Направите свемирску игру, део 4: Додавање ласера и детекција судара

Квиз пре предавања

Квиз пре предавања

У овој лекцији ћете научити како да пуцате ласере помоћу 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. Креирајте објекат у игри који изгледа као ласер када се притисне тастер.

Време за хлађење ласера

Ласер треба да се испаљује сваки пут када притиснете тастер, на пример 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 из серије свемирских игара да се подсетите на време за хлађење.

Шта треба направити

Узећете постојећи код (који сте требали очистити и рефакторисати) из претходне лекције и проширити га. Или започните са кодом из дела II или користите код из Део III - почетак.

савет: ласер са којим ћете радити већ се налази у вашем фолдеру са ресурсима и референциран је у вашем коду

  • Додајте детекцију судара, када ласер удари нешто, треба да се примењују следећа правила:
    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, а непријатељи нестају када их погодите. Браво!


🚀 Изазов

Додајте експлозију! Погледајте ресурсе игре у репозиторијуму Space Art и покушајте да додате експлозију када ласер погоди ванземаљца.

Квиз после предавања

Квиз после предавања

Преглед и самостално учење

Експериментишите са интервалима у вашој игри до сада. Шта се дешава када их промените? Прочитајте више о JavaScript временским догађајима.

Задатак

Истражите сударе


Одрицање од одговорности:
Овај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције Co-op Translator. Иако настојимо да обезбедимо тачност, молимо вас да имате у виду да аутоматизовани преводи могу садржати грешке или нетачности. Оригинални документ на изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не сносимо одговорност за било каква погрешна тумачења или неспоразуме који могу произаћи из коришћења овог превода.