О чем этот пример

В игровой разработке часто возникает необходимость остановить игровой мир — например, для показа меню паузы или замедления времени. Механизм паузы встроен в физический движок Matter.js в Phaser, но его использование имеет нюансы. В этой статье мы разберем рабочий пример управления паузой физики, объясним, как корректно ставить мир на паузу и возобновлять его, а также почему важно использовать `addCapture` для предотвращения побочных действий клавиши.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        // this.load.setBaseURL('https://cdn.phaserfiles.com/v385');
        this.load.image('ball', 'https://labs.phaser.io/assets/sprites/pangball.png');
    }

    create ()
    {
        this.matter.world.setBounds(0, 0, 800, 600, 32, true, true, false, true);

        for (let i = 0; i < 64; i++)
        {
            const ball = this.matter.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(-600, 0), 'ball');
            ball.setCircle();
            ball.setFriction(0.005);
            ball.setBounce(1);
        }

let p = false;
     this.input.keyboard.on("keydown-SPACE", (event) => {

      p = !p;

      if (! p) {
        this.matter.resume();
      } else {
        this.matter.pause();
      }
    });
    this.input.keyboard.addCapture("SPACE");
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#1d1d1d',
    parent: 'phaser-example',
    physics: {
        default: 'matter',
        matter: {
            enableSleeping: true
            
        }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка сцены и настройка физики

Вся логика примера находится в классе сцены. В методе preload загружается одно изображение мяча, которое будет использоваться для множества физических тел.

Ключевым моментом является конфигурация физики в объекте config. Мы указываем, что используем движок Matter.js (default: 'matter') и включаем в нем опцию enableSleeping. Это позволяет телам "засыпать" при отсутствии движения, что оптимизирует производительность.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#1d1d1d',
    parent: 'phaser-example',
    physics: {
        default: 'matter',
        matter: {
            enableSleeping: true
        }
    },
    scene: Example
};

Создание физического мира и тел

В методе create мы настраиваем мир и наполняем его объектами. Сначала задаются границы мира с помощью this.matter.world.setBounds(). Последние булевые параметры метода определяют, с каких сторон ставить стены; в нашем случае стены есть слева, справа и снизу.

Затем в цикле создается 64 мяча. Каждый мяч — это MatterImage, созданное через this.matter.add.image. Его начальная позиция по X случайна в пределах сцены, а по Y — может быть даже выше видимой области (от -600 до 0), чтобы мячи падали сверху.

Сразу после создания каждому телу задаются физические свойства: - setCircle() — определяет форму тела как круг (по умолчанию тело-прямоугольник). - setFriction(0.005) — устанавливает очень низкое трение. - setBounce(1) — задает идеально упругий отскок (коэффициент восстановления 1).

this.matter.world.setBounds(0, 0, 800, 600, 32, true, true, false, true);

for (let i = 0; i < 64; i++)
{
    const ball = this.matter.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(-600, 0), 'ball');
    ball.setCircle();
    ball.setFriction(0.005);
    ball.setBounce(1);
}

Логика переключения паузы по клавише SPACE

Здесь реализуется основная механика управления паузой. Объявляется флаг `p`, который отслеживает текущее состояние (пауза активна или нет).

На событие keydown-SPACE вешается обработчик, который инвертирует значение флага `p. В зависимости от нового состояния флага вызывается либоthis.matter.resume(), либоthis.matter.pause()`. Эти методы глобально останавливают и возобновляют вычисления физики для всего мира Matter.js.

let p = false;
this.input.keyboard.on("keydown-SPACE", (event) => {
    p = !p;
    if (!p) {
        this.matter.resume();
    } else {
        this.matter.pause();
    }
});

Зачем нужен addCapture и важные детали

Строка this.input.keyboard.addCapture("SPACE") — критически важная деталь для корректной работы в браузере. По умолчанию клавиша SPACE (пробел) имеет системное действие — прокрутка страницы. Если игровое окно встроено в веб-страницу, нажатие пробела будет одновременно ставить игру на паузу и прокручивать страницу вниз, что создает неприятный пользовательский опыт.

Метод addCapture() перехватывает событие от указанной клавиши, предотвращая его всплытие и выполнение действий браузера по умолчанию. Это стандартная практика для игровых управляющих клавиш.

Важно понимать, что this.matter.pause() и this.matter.resume() управляют только физическим движком. Анимации, таймеры и обновление логики сцены (в update) продолжают работать. Для полной паузы игры потребуется дополнительная логика.

this.input.keyboard.addCapture("SPACE");

Что попробовать дальше

Управление паузой физики в Phaser с Matter.js сводится к вызову двух методов: pause() и resume(). Пример демонстрирует надежный паттерн с флагом состояния и перехватом клавиши. Для экспериментов попробуйте

  1. Добавить визуальный индикатор состояния паузы (текст, затемнение)
  2. Связать паузу физики с остановкой анимаций спрайтов
  3. Реализовать систему "буллет-тайма" (замедления), модифицируя timeScale мира Matter через this.matter.world.setTimeScale(0.5)
  4. Управлять паузой для отдельных групп тел, а не для всего мира сразу