О чем этот пример
Взаимодействие с игровыми объектами часто требует тонкой настройки. По умолчанию Phaser использует всю текстуру спрайта как зону клика (hit area), что не всегда соответствует игровой логике. Например, для спрайта персонажа с оружием в руке вы можете захотеть, чтобы клик по оружию вызывал другую реакцию, чем клик по телу. Эта статья покажет, как точно контролировать область взаимодействия с любым объектом — уменьшая её до части текстуры или, наоборот, расширяя за её пределы. Вы научитесь адаптировать hit area под свои нужды, что особенно полезно для создания интерфейсов, интерактивных загадок и сложных игровых механик.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
rotation = 0.005;
hitarea2;
hitarea1;
atari3;
atari2;
atari1;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('atari1', 'assets/sprites/atari130xe.png');
this.load.image('atari2', 'assets/sprites/atari130xe-input.png');
}
create ()
{
// The texture is 220 x 104 pixels in size.
// By default, `setInteractive` will create a Rectangle with
// a position of 0 x 0 and a size of 220 x 104:
this.atari1 = this.add.image(150, 300, 'atari1').setInteractive();
// For this one, we'll change it so that the hit area is only over
// the keyboard part of the image (i.e. a smaller hit area than the texture size):
this.atari2 = this.add.image(400, 300, 'atari2').setInteractive();
// The 18 x 51 is the coordinate from the top-left of the texture
// The 183 x 39 is the width and height of the hit area rectangle
this.atari2.input.hitArea.setTo(18, 51, 183, 39);
// For this one, we'll change it so that the hit area is 60px bigger than the texture on each side
this.atari3 = this.add.image(650, 300, 'atari1').setInteractive();
// Coordinates are relative from the top-left, so we want out hit area to be
// an extra 60 pixels around the texture, so -30 from the x/y and + 60 to the texture width and height
this.atari3.input.hitArea.setTo(-30, -30, 220 + 60, 104 + 60);
// Debug output:
const text = this.add.text(10, 10, 'Click to toggle rotation\nMouse over the hit areas', { font: '16px Courier', fill: '#00ff00' });
this.atari1.on('pointerover', () => { text.setText('Over Image 1'); });
this.atari1.on('pointerout', () => { text.setText(''); });
this.atari2.on('pointerover', () => { text.setText('Over Image 2'); });
this.atari2.on('pointerout', () => { text.setText(''); });
this.atari3.on('pointerover', () => { text.setText('Over Image 3'); });
this.atari3.on('pointerout', () => { text.setText(''); });
// Draw the hit areas to a graphics object so we can visualize it:
this.hitarea1 = this.add.rectangle(this.atari1.x, this.atari1.y, this.atari1.width, this.atari1.height, 0x00ff00, 0.5);
this.hitarea2 = this.add.rectangle(this.atari3.x, this.atari3.y, this.atari3.width + 60, this.atari3.height + 60, 0xff00ff, 0.5);
this.input.on('pointerdown', () =>
{
this.rotation = (this.rotation === 0) ? 0.005 : 0;
});
}
update ()
{
this.atari1.rotation += this.rotation;
this.atari2.rotation += this.rotation;
this.atari3.rotation += this.rotation;
this.hitarea1.rotation += this.rotation;
this.hitarea2.rotation += this.rotation;
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Проблема: стандартная hit area не всегда подходит
Когда вы вызываете метод .setInteractive() для игрового объекта, Phaser автоматически создаёт прямоугольную зону взаимодействия (hit area), равную по размеру его текстуре. Координаты этого прямоугольника начинаются в точке (0, 0) относительно левого верхнего угла спрайта. Это удобно по умолчанию, но часто не соответствует желаемому поведению.
В примере мы видим три спрайта компьютера Atari:
* Первый (atari1) использует hit area по умолчанию.
* Второй (atari2) должен реагировать на наведение только в области клавиатуры.
* Третий (atari3) должен иметь зону взаимодействия больше, чем сам спрайт, чтобы упростить клик для игрока.
Для решения этой задачи используется свойство input.hitArea.
Доступ к hit area и метод setTo
Каждый интерактивный объект в Phaser имеет свойство input, которое содержит информацию о его взаимодействии, включая текущую hitArea. hitArea — это объект типа Phaser.Geom.Rectangle, который представляет собой прямоугольник.
Чтобы изменить его параметры, мы используем метод .setTo(x, y, width, height). Все координаты и размеры задаются относительно системы координат самого спрайта, где точка (0, 0) — это его левый верхний угол.
// Получаем доступ к зоне взаимодействия объекта atari2
this.atari2.input.hitArea
// Изменяем её параметры: x, y, ширина, высота
this.atari2.input.hitArea.setTo(18, 51, 183, 39)
Сценарий 1: Уменьшаем hit area (клик по клавиатуре)
Для спрайта atari2 мы хотим, чтобы реакция на наведение/клик срабатывала только при попадании в область клавиатуры на изображении. Исходная текстура имеет размер 220x104 пикселя. Визуально оценив спрайт, автор примера определил, что клавиатура начинается со смещения (18, 51) от левого верхнего угла текстуры и имеет размеры 183x39 пикселя.
// x=18, y=51 — смещение левого верхнего угла hit area от угла текстуры.
// width=183, height=39 — размеры прямоугольной зоны клика.
this.atari2.input.hitArea.setTo(18, 51, 183, 39);
Теперь события pointerover и pointerout будут срабатывать только когда курсор находится в пределах этого прямоугольника, несмотря на то, что игрок видит всю текстуру спрайта.
Сценарий 2: Расширяем hit area (упрощаем клик)
Иногда спрайт слишком мал для удобного клика, особенно в мобильных играх. В этом случае hit area можно сделать больше, чем сама текстура. Для спрайта atari3 мы хотим добавить по 30 пикселей отступа с каждой стороны.
Исходный размер текстуры: 220x104. Нужный размер hit area: (220+60) x (104+60) = 280x164. Чтобы такой прямоугольник был центрирован относительно спрайта, его левый верхний угол должен быть смещён на -30 пикселей по обеим осям.
// x=-30, y=-30 — смещаем угол hit area за пределы текстуры.
// width=280, height=164 — итоговые размеры увеличенной зоны.
this.atari3.input.hitArea.setTo(-30, -30, 220 + 60, 104 + 60);
Теперь игроку будет гораздо проще попасть по объекту, так как невидимая область взаимодействия выходит за границы визуального изображения.
Визуализация и отладка
Поскольку hit area невидима, для отладки крайне полезно её визуализировать. В примере это сделано с помощью полупрозрачных прямоугольников (this.add.rectangle), которые создаются в методе create и вращаются вместе со спрайтами в update.
// Визуализация hit area по умолчанию (совпадает с atari1)
this.hitarea1 = this.add.rectangle(this.atari1.x, this.atari1.y, this.atari1.width, this.atari1.height, 0x00ff00, 0.5);
// Визуализация увеличенной hit area (совпадает с atari3)
this.hitarea2 = this.add.rectangle(this.atari3.x, this.atari3.y, this.atari3.width + 60, this.atari3.height + 60, 0xff00ff, 0.5);
// В update эти прямоугольники вращаются вместе со спрайтами
this.hitarea1.rotation += this.rotation;
this.hitarea2.rotation += this.rotation;
Также для наглядности в примере текст на экране меняется при наведении курсора на hit area каждого из трёх объектов.
Что попробовать дальше
Умение управлять hit area — это ключ к созданию отзывчивого и точного геймплея. Вы можете создавать сложные интерактивные объекты, где разные части спрайта реагируют по-разному, или, наоборот, упрощать взаимодействие для игрока.
Идеи для экспериментов:
1. Создайте спрайт-карту, где клик по разным странам вызывает разные события, используя несколько hit area на одном объекте (через setInteractive с параметром hitArea).
2. Реализуйте нестандартную форму hit area (например, круглую), используя setInteractive с объектом Phaser.Geom.Circle.
3. Динамически меняйте размер hit area в зависимости от состояния игры (например, увеличивайте зону клика по боссу, когда у него мало здоровья).
