Браузерные игры
April 15, 2022

JS + Phaser пишем игру с Дино (часть 4) 🦖

Перед тем как начать:

В прошлой части мы с вами добавили противников для нашего Дино, а так же разобрались с тем, как делать респаун объектов по своему желанию, если вы это пропустили, то советую вернуться к части 3.

Код, который уже готов живет тут.

Противников мы с вами добавили в предыдущей части, а сегодня займемся тем, чтобы эти противники могли нанести нам урон...

А именно научимся обрабатывать коллизии и определять конец нашей игры)

Начнем отслеживать коллизии

И так, для начала нам нужно как-то определить, что Дино столкнулся с другими объектами, для этого в конструкторе добавим строчку с инициализацией функции, которая будет за это отвечать:

create() {
    // Остальной код функции
    this.initAnims();
    
    // Добавим еще одну функцию илициализатов
    this.initColliders();    

    this.createControll();
    this.initStartTrigger();
}

Теперь давайте начнем создавать объявленную функцию:

  initColliders() {
    this.physics.add.collider(this.dino, this.obsticles, () => { // 1
      this.physics.pause(); // 2
      this.isGameRunning = false; // 3
      this.anims.pauseAll(); // 4
      this.dino.setTexture('dino-hurt'); // 5
      this.respawnTime = 0; // 6
      this.gameSpeed = 10; // 7
    }, null, this);
  }

  1. collider - функция, которая позволяет нам добавить функцию обработчик на ситуации коллизии объектов.
  2. Для начала при столкновении мы с вами остановим всю физику в игре
  3. Скажем что сейчас игра не идет
  4. Остановим все анимации, которые у нас сейчас играют
  5. Навесим на динозавра погибающего спрайта
  6. Откатим време респауна
  7. И откатим скорость игры к дефолтному значению

Немного оптимизации

После того как препятствия пропадают из нашей области видимости обработчик этой функции на них сохраняется и код продолжает жить в памяти, из-за того что мы никак ее не высвобождаем. Давайте исправим это!

Для этого нам нужно добавить убийство этих объектов в нашу функцию update():

  update(time, delta) {
    // Остальной код функции
    
    this.obsticles.getChildren().forEach(obsticle => {
      // Если препятствие вышло за границы
      if (obsticle.getBounds().right < 0) {
        // Метод для вызова деструктора
        obsticle.destroy();
      }
    });
 }

Добавим перезапуск игры

После того как произошла коллизия нам бы как-то игру перезапустить, для этого давайте в конструкторе создадим еще несколько объектов:

  create() {
    // Остальной код функции
    
    this.gameOverScreen = this.add.container(width / 2, height / 2 - 50);
    this.gameOverText = this.add.image(0, 0, 'game-over');
    this.restart = this.add.image(0, 80, 'restart').setInteractive();
    
    this.gameOverScreen.add([
      this.gameOverText,  this.restart
    ]);
 }

Метод setInteractive() - дает нам возможность потом взаимодействовать с объектом, а в нашем случае - обрабатывать нажатия.

Если открыть браузер, то мы сразу увидем наш экран для конца игры:

Это не совсем то что мы хотим, поэтому давайте на момент начала игры спрячем этот экран, установив ему .setAlpha(0):

  create() {
    // Остальной код функции
    
    this.gameOverScreen = this.add.container(width / 2, height / 2 - 50).setAlpha(0);
    this.gameOverText = this.add.image(0, 0, 'game-over');
    this.restart = this.add.image(0, 80, 'restart').setInteractive();
    
    this.gameOverScreen.add([
      this.gameOverText,  this.restart
    ]);
 }

А вот когда игра заканчивается - в функции обработки коллизии, нам нужно наоборот показать этот экран:

  initColliders() {
    this.physics.add.collider(this.dino, this.obsticles, () => {
      this.physics.pause();
      this.isGameRunning = false;
      this.anims.pauseAll();
      this.dino.setTexture('dino-hurt');
      this.respawnTime = 0;
      this.gameSpeed = 20;
      
      // Показываем экран
      this.gameOverScreen.setAlpha(1);
    }, null, this);
  }

Сейчас у нас выходит следующее:

Обрабатываем нажатие на кнопку

Ну что же, для полноценного рестарта не хватает только перезапуска по кнопке, поэтому давайте добавим этот обработчик в функции createControll():

  createControll() {
    // Остальной код функции
    
    this.restart.on('pointerdown', () => { // 1
      this.dino.setVelocityY(0); // 2
      this.dino.body.height = 92; // 3
      this.dino.body.offset.y = 0; // 4
      this.physics.resume(); // 5
      this.obsticles.clear(true, true); // 6
      this.isGameRunning = true; // 7
      this.gameOverScreen.setAlpha(0); // 8
      this.anims.resumeAll(); // 9
    });
 }

  1. Функция обработчик нажатия на кнопку
  2. Если наш Дино прыгал - вернем его на землю
  3. Если он пригибался - вернем исходную высоту
  4. Так же нужно просто откатить к состоянию, которое у нас было на начало игры
  5. Возобновим всю физику в игре
  6. Уберем всех врагов со сцены
  7. Запустим игру
  8. Спрячем экран конца игры
  9. Возобновим анимацию

На этом я закончу четвертую часть из цикла статей по созданию игры с Дино, надеюсь вам было интересно и вы попробовали сами с нуля создать свою игру!

Вы можете найти код для этого урока тут

JS + Phaser пишем игру с Дино (часть 5) 🦖->