О чем этот пример
Современные игры и приложения часто требуют поддержки нескольких одновременных касаний — для управления несколькими персонажами, совместного взаимодействия или реализации сложных жестов. Встроенная система ввода Phaser изначально рассчитана на один указатель (мышь или первое касание). Однако её легко расширить для полноценной мультитач-обработки. В этой статье мы разберём простой пример, который демонстрирует, как добавить несколько указателей и сделать интерактивными несколько игровых объектов, реагирующих на независимые касания. Это полезно для создания панелей с перетаскиваемыми элементами, мультиплеерных интерфейсов на одном экране или музыкальных инструментов.
Версия 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.setPath('assets/input');
this.load.image([ 'p', 'h', 'a', 's', 'e', 'r' ]);
}
create ()
{
this.input.addPointer(5);
const p = this.add.image(0, 0, 'p').setInteractive();
const h = this.add.image(0, 0, 'h').setInteractive();
const a = this.add.image(0, 0, 'a').setInteractive();
const s = this.add.image(0, 0, 's').setInteractive();
const e = this.add.image(0, 0, 'e').setInteractive();
const r = this.add.image(0, 0, 'r').setInteractive();
Phaser.Actions.GridAlign([ p, h, a, s, e, r ], {
width: 6,
cellWidth: 132,
cellHeight: 200,
x: 68,
y: 300
});
this.input.on('gameobjectdown', (pointer, gameObject) =>
{
gameObject.setTint(0xffff00, 0xffff00, 0xff0000, 0xff0000).setTintMode(Phaser.TintModes.FILL);
});
this.input.on('gameobjectup', (pointer, gameObject) =>
{
gameObject.clearTint();
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#efefef',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка ассетов и добавление указателей
Первым делом в методе preload мы загружаем шесть изображений букв, составляющих слово 'phaser'. Обратите внимание на использование load.image с массивом названий — это компактный способ загрузить несколько файлов за один вызов.
Ключевой момент для мультитача происходит в create. Система ввода Phaser (this.input) по умолчанию имеет один активный указатель. Метод addPointer добавляет новые указатели в пул. В нашем примере мы добавляем пять, получая в сумме шесть (один исходный + пять новых). Это позволяет одновременно отслеживать до шести независимых касаний на экране.
this.input.addPointer(5);
Далее мы создаём шесть объектов Image, по одному на каждую букву, и сразу делаем их интерактивными с помощью .setInteractive(). Это необходимо, чтобы объекты могли генерировать события ввода.
Автоматическое выравнивание объектов
Вручную расставлять шесть изображений по координатам неудобно. Phaser предоставляет удобный хелпер Phaser.Actions.GridAlign для автоматического размещения массива объектов в виртуальную сетку.
Мы передаём массив наших изображений и объект конфигурации. Параметр width: 6 указывает, что все объекты должны быть размещены в одну строку. cellWidth и cellHeight задают размер ячейки для каждого объекта, а `xиy` — стартовую точку для всей сетки.
Phaser.Actions.GridAlign([ p, h, a, s, e, r ], {
width: 6,
cellWidth: 132,
cellHeight: 200,
x: 68,
y: 300
});
В результате все шесть букв аккуратно выстраиваются в горизонтальный ряд на заданной высоте.
Обработка событий нажатия и отпускания
Теперь нужно «оживить» буквы, чтобы они реагировали на касания. Мы подписываемся на два события системы ввода: gameobjectdown (касание началось или нажата кнопка мыши на объекте) и gameobjectup (касание завершилось или кнопка мыши отпущена).
В обработчике gameobjectdown объект, на котором произошло событие, получает tint (оттенок) с помощью setTint. Цвета передаются четырьмя аргументами, соответствующими углам объекта (top-left, top-right, bottom-left, bottom-right), что создаёт градиентный эффект. Важный момент — мы также устанавливаем режим tint через setTintMode(Phaser.TintModes.FILL). Без этого, в зависимости от текстуры, tint может не применяться или применяться некорректно.
this.input.on('gameobjectdown', (pointer, gameObject) => {
gameObject.setTint(0xffff00, 0xffff00, 0xff0000, 0xff0000).setTintMode(Phaser.TintModes.FILL);
});
В обработчике gameobjectup tint просто сбрасывается, возвращая объекту исходный вид.
this.input.on('gameobjectup', (pointer, gameObject) => {
gameObject.clearTint();
});
Поскольку мы добавили несколько указателей, эти события будут корректно срабатывать для каждого касания независимо, позволяя одновременно «нажимать» несколько букв разными пальцами.
Конфигурация и запуск игры
Сцена готова, осталось настроить и запустить экземпляр игры Phaser. Конфигурационный объект задаёт базовые параметры: тип рендерера (Phaser.AUTO выбирает WebGL или Canvas автоматически), родительский HTML-элемент, размеры холста, цвет фона и класс нашей сцены.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#efefef',
scene: Example
};
const game = new Phaser.Game(config);
После создания экземпляра Phaser.Game сцена автоматически проходит через свои жизненные циклы (preload, create, update), и на экране появляется интерактивная мультитач-панель.
Что попробовать дальше
Всего в несколько строк кода мы превратили статичные изображения в мультитач-интерактивную панель. Основной секрет — вызов this.input.addPointer() для расширения пула указателей. Этот механизм открывает двери для множества экспериментов: попробуйте добавить логику перетаскивания объектов с помощью событий drag, измените реакцию объектов в зависимости от индекса pointer.id (чтобы различать пальцы), или создайте сложные жесты, отслеживая движение нескольких указателей одновременно. Такая техника отлично подходит для казуальных игр, образовательных приложений и интерактивных инсталляций на сенсорных экранах.
