О чем этот пример
Физика и визуальные эффекты часто существуют отдельно друг от друга. Но что, если сделать частицы чувствительными к физическим телам? В этой статье мы создадим зону смерти для системы частиц, используя хит-тест физического тела Arcade. Это позволит частицам исчезать при столкновении с движущимся объектом, создавая эффект поглощения или разрушения. Пример особенно полезен для игр, где нужно визуально подчеркнуть взаимодействие: например, вражеский щит поглощает выстрелы, или черная дыра затягивает частицы. Мы разберем, как связать `Arcade.Body` с `DeathZone`, не прибегая к сложным проверкам вручную.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.55.2.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
block;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
const source = {
contains: (x, y) => this.block.body.hitTest(x, y)
};
const particles = this.add.particles('flares');
particles.createEmitter({
frame: [ 'red', 'green', 'blue' ],
x: 400,
y: 100,
speed: 300,
gravityY: 400,
lifespan: 4000,
scale: 0.4,
blendMode: 'ADD',
deathZone: { type: 'onEnter', source: source }
});
this.block = this.physics.add.image(400, 100, 'block');
this.block.setGravity(0, 200);
this.block.setVelocity(100, 200);
this.block.setBounce(1, 1);
this.block.setCollideWorldBounds(true);
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
physics: { default: 'arcade' },
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
В методе preload загружаем необходимые ресурсы. Атлас flares содержит текстуры для частиц, а изображение block будет нашим физическим объектом.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
this.load.image('block', 'assets/sprites/block.png');
}
Создание источника для зоны смерти
Ключевой момент — создание объекта source с методом contains. Этот метод будет вызываться системой частиц для каждой частицы, чтобы определить, находится ли она внутри зоны смерти. Мы используем this.block.body.hitTest(x, y) — встроенный метод Arcade Physics, который проверяет, попадает ли точка (координаты частицы) в границы физического тела. Важно создать source до инициализации блока, поэтому объявляем его через ссылку на будущий объект.
const source = {
contains: (x, y) => this.block.body.hitTest(x, y)
};
Настройка эмиттера частиц
Создаем систему частиц и эмиттер. В параметре deathZone указываем type: 'onEnter', что означает уничтожение частицы в момент попадания в зону. source — наш объект с методом contains. Частицы будут испускаться из точки (400, 100) с разными цветами (frame), скоростью и гравитацией.
const particles = this.add.particles('flares');
particles.createEmitter({
frame: [ 'red', 'green', 'blue' ],
x: 400,
y: 100,
speed: 300,
gravityY: 400,
lifespan: 4000,
scale: 0.4,
blendMode: 'ADD',
deathZone: { type: 'onEnter', source: source }
});
Создание и настройка физического блока
Теперь создаем сам блок как физический объект с помощью this.physics.add.image. Устанавливаем ему гравитацию, начальную скорость, упругость (setBounce) и включение столкновений с границами мира. Блок будет двигаться, отскакивать от стен, а его тело (body) — использоваться в методе hitTest из source.
this.block = this.physics.add.image(400, 100, 'block');
this.block.setGravity(0, 200);
this.block.setVelocity(100, 200);
this.block.setBounce(1, 1);
this.block.setCollideWorldBounds(true);
Конфигурация игры и запуск
В конфигурации игры обязательно указываем physics: { default: 'arcade' }, чтобы активировать Arcade Physics. Без этого физическое тело у блока не создастся, и метод hitTest будет недоступен.
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
physics: { default: 'arcade' },
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Мы связали систему частиц с физическим телом, используя deathZone и метод hitTest. Это мощный паттерн для создания динамических визуальных эффектов, зависящих от игровой логики. Для экспериментов попробуйте изменить type зоны смерти на 'onLeave', чтобы частицы уничтожались при выходе из тела. Или используйте несколько источников для сложных составных зон. Можно применить этот подход к группам тел (PhysicsGroup) для массовых взаимодействий.
