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
softchris bde9da6dad
🌐 Update translations via Co-op Translator
1 month ago
..
solution 🌐 Update translations via Co-op Translator 3 months ago
your-work 🌐 Update translations via Co-op Translator 3 months ago
README.md 🌐 Update translations via Co-op Translator 1 month ago
assignment.md 🌐 Update translations via Co-op Translator 1 month ago

README.md

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

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

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

Сетите се тренутка у "Ратовима звезда" када су Лукови протонски торпеда погодили издувни порт Звезде смрти. Та прецизна детекција судара променила је судбину галаксије! У играма, детекција судара функционише на исти начин - одређује када објекти међусобно делују и шта се дешава након тога.

У овој лекцији, додаћете ласерско оружје својој свемирској игри и имплементирати детекцију судара. Баш као што планери мисија НАСА-е израчунавају путање свемирских летелица како би избегли отпад, научићете како да детектујете када се објекти у игри укрштају. Разложићемо ово на управљиве кораке који се надовезују један на други.

На крају, имаћете функционалан борбени систем где ласери уништавају непријатеље, а судари покрећу догађаје у игри. Ови исти принципи детекције судара користе се у свему, од симулација физике до интерактивних веб интерфејса.

Урадите мало истраживање о првој компјутерској игри икада написаној. Која је била њена функционалност?

Детекција судара

Детекција судара функционише као сензори близине на лунарном модулу Аполо - стално проверава растојања и покреће упозорења када се објекти превише приближе. У играма, овај систем одређује када објекти међусобно делују и шта би требало да се догоди након тога.

Приступ који ћемо користити третира сваки објекат у игри као правоугаоник, слично као што системи контроле ваздушног саобраћаја користе поједностављене геометријске облике за праћење авиона. Овај метод са правоугаоницима може изгледати основно, али је рачунарски ефикасан и добро функционише за већину сценарија у игри.

Представљање правоугаоника

Сваки објекат у игри треба координатне границе, слично као што је ровер Марс Патхфиндер мапирао своју локацију на површини Марса. Ево како дефинишемо те координате граница:

rectFromGameObject() {
  return {
    top: this.y,
    left: this.x,
    bottom: this.y + this.height,
    right: this.x + this.width
  }
}

Хајде да ово разложимо:

  • Горња ивица: То је само место где ваш објекат вертикално почиње (његова y позиција)
  • Лева ивица: Место где хоризонтално почиње (његова x позиција)
  • Доња ивица: Додајте висину на y позицију - сада знате где се завршава!
  • Десна ивица: Додајте ширину на x позицију - и добили сте комплетну границу

Алгоритам за пресек

Детекција пресека правоугаоника користи логику сличну оној коју телескоп Хабл користи да утврди да ли се небески објекти преклапају у његовом видном пољу. Алгоритам проверава раздвајање:

function intersectRect(r1, r2) {
  return !(r2.left > r1.right ||
    r2.right < r1.left ||
    r2.top > r1.bottom ||
    r2.bottom < r1.top);
}

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

  • Да ли је правоугаоник 2 потпуно десно од правоугаоника 1?
  • Да ли је правоугаоник 2 потпуно лево од правоугаоника 1?
  • Да ли је правоугаоник 2 потпуно испод правоугаоника 1?
  • Да ли је правоугаоник 2 потпуно изнад правоугаоника 1?

Ако ниједан од ових услова није тачан, правоугаоници морају бити преклопљени. Овај приступ одражава начин на који оператери радара одређују да ли су два авиона на безбедним растојањима.

Управљање животним циклусима објеката

Када ласер погоди непријатеља, оба објекта морају бити уклоњена из игре. Међутим, брисање објеката током петље може изазвати падове - лекција научена на тежи начин у раним компјутерским системима као што је Аполо рачунар за навигацију. Уместо тога, користимо приступ "означи за брисање" који безбедно уклања објекте између кадрова.

Ево како означавамо нешто за уклањање:

// Mark object for removal
enemy.dead = true;

Зашто овај приступ функционише:

  • Означавамо објекат као "мртав", али га не бришемо одмах
  • Ово омогућава тренутном кадру игре да се безбедно заврши
  • Нема падова због покушаја коришћења нечега што је већ уклоњено!

Затим филтрирамо означене објекте пре следећег циклуса рендеровања:

gameObjects = gameObjects.filter(go => !go.dead);

Шта ради ово филтрирање:

  • Креира нову листу само са "живим" објектима
  • Избацује све што је означено као мртво
  • Одржава вашу игру да ради глатко
  • Спречава нагомилавање меморије од уништених објеката

Имплементација механике ласера

Ласерски пројектили у играма функционишу на истом принципу као фотонски торпеда у "Звезданим стазама" - то су дискретни објекти који путују праволинијски док не ударе у нешто. Сваки притисак на размакницу ствара нови ласерски објекат који се креће преко екрана.

Да би ово функционисало, потребно је координисати неколико различитих делова:

Кључне компоненте за имплементацију:

  • Креирање ласерских објеката који се појављују из позиције хероја
  • Обрада уноса са тастатуре за покретање креирања ласера
  • Управљање кретањем ласера и животним циклусом
  • Имплементација визуелног приказа ласерских пројектила

Имплементација контроле брзине пуцања

Неограничене брзине пуцања би преоптеретиле мотор игре и учиниле игру превише лаком. Прави оружани системи се суочавају са сличним ограничењима - чак су и фазери USS Enterprise-а морали да се напуне између пуцања.

Имплементираћемо систем хлађења који спречава прекомерно пуцање, а истовремено одржава одзивне контроле:

class Cooldown {
  constructor(time) {
    this.cool = false;
    setTimeout(() => {
      this.cool = true;
    }, time);
  }
}

class Weapon {
  constructor() {
    this.cooldown = null;
  }
  
  fire() {
    if (!this.cooldown || this.cooldown.cool) {
      // Create laser projectile
      this.cooldown = new Cooldown(500);
    } else {
      // Weapon is still cooling down
    }
  }
}

Како систем хлађења функционише:

  • Када се креира, оружје постаје "вруће" (још не може да пуца)
  • Након периода чекања, постаје "хладно" (спремно за пуцање)
  • Пре пуцања, проверавамо: "Да ли је оружје хладно?"
  • Ово спречава прекомерно кликање, а истовремено одржава одзивност контрола

Погледајте лекцију 1 у серији свемирских игара да се подсетите на системе хлађења.

Изградња система за детекцију судара

Проширићете постојећи код своје свемирске игре како бисте креирали систем за детекцију судара. Као аутоматизовани систем за избегавање судара Међународне свемирске станице, ваша игра ће континуирано пратити позиције објеката и реаговати на њихове пресеке.

Полазећи од кода из претходне лекције, додаћете детекцију судара са специфичним правилима која регулишу интеракције објеката.

💡 Савет: Спрайт ласера је већ укључен у вашу фасциклу са ресурсима и референциран у вашем коду, спреман за имплементацију.

Правила судара која треба имплементирати

Механике игре које треба додати:

  1. Ласер погађа непријатеља: Објекат непријатеља се уништава када га погоди ласерски пројектил
  2. Ласер погађа границу екрана: Ласер се уклања када стигне до горње ивице екрана
  3. Судар непријатеља и хероја: Оба објекта се уништавају када се укрсте
  4. Непријатељ стиже до дна: Услов за крај игре када непријатељи стигну до дна екрана

Постављање развојног окружења

Добре вести - већ смо припремили већину основа за вас! Сви ваши ресурси за игру и основна структура чекају у подфасцикли your-work, спремни да додате кул функције за детекцију судара.

Структура пројекта

-| assets
  -| enemyShip.png
  -| player.png
  -| laserRed.png
-| index.html
-| app.js
-| package.json

Разумевање структуре фолдера:

  • Садржи све слике спрайтова потребне за објекте у игри
  • Укључује главни HTML документ и JavaScript датотеку апликације
  • Обезбеђује конфигурацију пакета за локални сервер за развој

Покретање локалног сервера за развој

Идите у фасциклу свог пројекта и покрените локални сервер:

cd your-work
npm start

Ова секвенца команди:

  • Прелази у фасциклу вашег радног пројекта
  • Покреће локални HTTP сервер на http://localhost:5000
  • Сервира ваше датотеке игре за тестирање и развој
  • Омогућава развој уживо са аутоматским освежавањем

Отворите свој претраживач и идите на http://localhost:5000 да бисте видели тренутно стање своје игре са херојем и непријатељима приказаним на екрану.

Корак по корак имплементација

Као систематски приступ који је НАСА користила за програмирање свемирског брода Војаџер, имплементираћемо детекцију судара методично, градећи сваки компонент корак по корак.

1. Додајте границе судара правоугаоника

Прво, научимо наше објекте у игри како да опишу своје границе. Додајте овај метод у своју класу 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
  );
}

Овај алгоритам функционише тако што:

  • Тестира четири услова раздвајања између правоугаоника
  • Враћа false ако је било који услов раздвајања тачан
  • Указује на судар када не постоји раздвајање
  • Користи логику негације за ефикасно тестирање пресека

3. Имплементација система за пуцање ласера

Ево где ствари постају узбудљиве! Поставимо систем за пуцање ласера.

Константе порука

Прво, дефинишимо неке типове порука како би различити делови наше игре могли да комуницирају:

KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",

Ове константе обезбеђују:

  • Стандартизацију назива догађаја широм апликације
  • Омогућавају конзистентну комуникацију између система игре
  • Спречавају грешке у регистрацији обрађивача догађаја
Обрада уноса са тастатуре

Додајте детекцију притиска на размакницу у свој слушалац догађаја за тастатуру:

} else if(evt.keyCode === 32) {
  eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}

Овај обрађивач уноса:

  • Детектује притиске на размакницу користећи keyCode 32
  • Емитује стандардизовану поруку догађаја
  • Омогућава раздвојену логику пуцања
Постављање слушаоца догађаја

Региструјте понашање пуцања у функцији initGame():

eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
 if (hero.canFire()) {
   hero.fire();
 }
});

Овај слушалац догађаја:

  • Реагује на догађаје притиска на размакницу
  • Проверава статус хлађења за пуцање
  • Покреће креирање ласера када је дозвољено

Додајте обраду судара за интеракције ласера и непријатеља:

eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
  first.dead = true;
  second.dead = true;
});

Овај обрађивач судара:

  • Прима податке о догађају судара са оба објекта
  • Означава оба објекта за уклањање
  • Обезбеђује правилно чишћење након судара

4. Креирајте класу Laser

Имплементирајте ласерски пројектил који се креће нагоре и управља својим животним циклусом:

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);
  }
}

Ова имплементација класе:

  • Проширује GameObject да наследи основну функционалност
  • Поставља одговарајуће димензије за спрайт ласера
  • Креира аутоматско кретање нагоре користећи setInterval()
  • Обрађује самоуништење када стигне до врха екрана
  • Управља сопственим временом анимације и чишћењем

5. Имплементација система за детекцију судара

Креирајте свеобухватну функцију за детекцију судара:

function updateGameObjects() {
  const enemies = gameObjects.filter(go => go.type === 'Enemy');
  const lasers = gameObjects.filter(go => go.type === "Laser");
  
  // Test laser-enemy collisions
  lasers.forEach((laser) => {
    enemies.forEach((enemy) => {
      if (intersectRect(laser.rectFromGameObject(), enemy.rectFromGameObject())) {
        eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
          first: laser,
          second: enemy,
        });
      }
    });
  });

  // Remove destroyed objects
  gameObjects = gameObjects.filter(go => !go.dead);
}

Овај систем за детекцију судара:

  • Филтрира објекте игре по типу ради ефикасног тестирања
  • Тестира сваки ласер против сваког непријатеља за пресеке
  • Емитује догађаје судара када се пресек детектује
  • Чисти уништене објекте након обраде судара

⚠️ Важно: Додајте updateGameObjects() у главну петљу игре у window.onload да бисте омогућили детекцију судара.

6. Додајте систем хлађења у класу Hero

Унапредите класу 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;
  }
}

Разумевање унапређене класе Hero:

  • Иницијализује тајмер хлађења на нулу (спреман за пуцање)
  • Креира ласерске објекте позициониране изнад брода хероја
  • Поставља период хлађења да спречи прекомерно пуцање
  • Смањује тајмер хлађења користећи ажурирања заснована на интервалу
  • Обезбеђује проверу статуса пуцања кроз метод canFire()

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