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, ширину и висину.

Ако се два правоугаоника, тј. херој и непријатељ пресеку, имате судар. Шта би требало да се догоди након тога зависи од правила игре. Да бисте имплементирали детекцију судара, потребно је следеће:

  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. Иако настојимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати меродавним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу настати услед коришћења овог превода.