О чем этот пример
При разработке игр часто возникает необходимость динамически удалять объекты со сцены, особенно те, которые участвуют в физическом движке. Неправильное удаление может привести к утечкам памяти или ошибкам при попытке взаимодействия с уже несуществующим телом. В этой статье мы разберем официальный пример Phaser, который показывает корректный способ уничтожения физического тела с помощью метода `destroy()`. Вы научитесь безопасно удалять объекты, останавливать связанные с ними слушатели событий и управлять игровой логикой при уничтожении сущностей.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
const block = this.physics.add.image(400, 100, 'block');
block.setVelocity(100, 200);
block.setBounce(0.9);
block.setCollideWorldBounds(true);
block.setInteractive();
const text = this.add.text(10, 10, 'Clicks: 5', { font: '16px Courier', fill: '#00ff00' });
let i = 5;
this.input.on('pointerdown', function ClickNuke ()
{
i--;
text.setText(`Clicks: ${i}`);
if (i === 0)
{
block.destroy();
this.input.off('pointerdown', ClickNuke);
}
else
{
block.setVelocity(Phaser.Math.Between(-300, 300), -600);
}
}, this);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
debug: true,
gravity: { y: 200 }
}
},
scene: Example
};
const game = new Phaser.Game(config);
Инициализация сцены и физики
В начале кода определяется класс сцены Example. В методе preload() загружается спрайт 'block'.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
Конфигурация игры включает физический движок Arcade с гравитацией и режимом отладки, что позволяет видеть хитбоксы тел.
physics: {
default: 'arcade',
arcade: {
debug: true,
gravity: { y: 200 }
}
},
Создание интерактивного физического тела
В методе create() создается основная сущность — физический спрайт 'block'. Ему сразу задаются начальные физические свойства.
const block = this.physics.add.image(400, 100, 'block');
block.setVelocity(100, 200);
block.setBounce(0.9);
block.setCollideWorldBounds(true);
Ключевой момент: спрайт делается интерактивным с помощью setInteractive(). Это позволяет позже обрабатывать клики по нему. Также создается текстовый объект для отображения счетчика.
block.setInteractive();
const text = this.add.text(10, 10, 'Clicks: 5', { font: '16px Courier', fill: '#00ff00' });
Логика кликов и уничтожения тела
На глобальное событие указателя pointerdown вешается обработчик ClickNuke. Он уменьшает счетчик `i` и обновляет текст.
let i = 5;
this.input.on('pointerdown', function ClickNuke () {
i--;
text.setText(`Clicks: ${i}`);
// ...
}, this);
Если счетчик достиг нуля, тело block уничтожается методом destroy(). Этот метод полностью удаляет объект из игры: он убирает его из физического мира, отключает все слушатели событий и освобождает ресурсы.
if (i === 0)
{
block.destroy();
this.input.off('pointerdown', ClickNuke);
}
Важно отметить, что сразу после уничтожения тела отключается и сам слушатель события pointerdown, чтобы предотвратить попытки взаимодействия с несуществующим объектом. Это хорошая практика для чистки событий.
Поведение до уничтожения
Пока счетчик не равен нулю, при каждом клике телу задается новый случайный импульс. Это демонстрирует интерактивность объекта до его удаления.
else
{
block.setVelocity(Phaser.Math.Between(-300, 300), -600);
}
Функция Phaser.Math.Between() генерирует случайное значение для горизонтальной скорости, а вертикальная скорость всегда резко направлена вверх (-600), создавая эффект "подбрасывания" блока при клике.
Что попробовать дальше
Метод destroy() является правильным и безопасным способом полного удаления игрового объекта из Phaser. Он обеспечивает корректную работу сборщика мусора и предотвращает ошибки. Важно помнить об очистке связанных событий, как показано в примере с this.input.off(). Для экспериментов попробуйте
- Уничтожать тело не по счетчику, а при достижении им определенной области на экране
- Создавать несколько тел и удалять их при столкновении друг с другом, используя
collider - Визуализировать процесс уничтожения, добавив частицы или звуковой эффект в момент вызова
destroy()
