О чем этот пример
Создание интерактивных игр — это, в первую очередь, отклик на действия игрока. Одна из самых базовых, но мощных возможностей — позволить игроку рисовать или размещать объекты прямо в игровом мире с помощью мыши. Этот простой механизм лежит в основе редакторов уровней, рисовалок, игр о строительстве и многих казуальных проектов. В статье на примере кода из официального репозитория 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.spritesheet('balls', 'assets/sprites/balls.png', { frameWidth: 17, frameHeight: 17 });
}
create ()
{
this.input.on('pointermove', function (pointer)
{
if (pointer.isDown)
{
this.add.image(pointer.x, pointer.y, 'balls', Phaser.Math.Between(0, 5));
}
}, this);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
Вся логика в Phaser размещается внутри методов сцены (Scene). На этапе preload мы загружаем ресурсы, необходимые для работы. В данном примере загружается не просто изображение, а спрайтшит (spritesheet) — единая картинка, содержащая несколько кадров (спрайтов).
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.spritesheet('balls', 'assets/sprites/balls.png', { frameWidth: 17, frameHeight: 17 });
}
Метод setBaseURL задает базовый путь для загрузки. Далее метод load.spritesheet загружает изображение по ключу 'balls'. Третий аргумент — объект конфигурации, который указывает движку, как «нарезать» большую картинку на отдельные кадры размером 17x17 пикселей. После загрузки мы сможем обращаться к каждому из этих кадров по его индексу (от 0 до N).
Обработка ввода и событие pointermove
Основная логика размещения объектов происходит в методе create, который выполняется один раз после загрузки ресурсов. Здесь мы настраиваем взаимодействие с пользователем.
Ключевой элемент — система ввода Phaser (this.input). Мы используем метод on, чтобы подписаться на конкретное событие. Событие 'pointermove' генерируется каждый раз, когда пользователь перемещает указатель (мышь или касание) над игровым холстом.
create ()
{
this.input.on('pointermove', function (pointer)
{
// Логика будет здесь
}, this);
}
Обратите внимание на третий аргумент this, переданный в метод on. Он задает контекст (значение this) для callback-функции. Без этого контекст внутри функции был бы потерян, и мы не смогли бы вызвать, например, this.add.image.
Условие отрисовки и создание спрайта
Однако нам нужно рисовать не просто при движении мыши, а только когда кнопка мыши нажата. Для этого у объекта pointer, который передается в функцию-обработчик, есть свойство isDown.
if (pointer.isDown)
{
this.add.image(pointer.x, pointer.y, 'balls', Phaser.Math.Between(0, 5));
}
Если условие выполняется, мы создаем новый спрайт. Метод this.add.image принимает четыре аргумента:
1. Координата X (pointer.x).
2. Координата Y (pointer.y).
3. Ключ текстуры ('balls').
4. Индекс кадра (frame) из спрайтшита.
Для выбора кадра используется Phaser.Math.Between(0, 5). Эта функция возвращает случайное целое число в заданном диапазоне. Таким образом, при каждом вызове на холсте будет появляться шар одного из шести случайных цветов, что создает простой визуальный эффект.
Конфигурация и запуск игры
Код сцены — это только часть приложения. Чтобы игра запустилась, необходимо создать конфигурационный объект и передать его в конструктор Phaser.Game.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
В конфиге мы указываем:
- type: Рендерер (Phaser.AUTO выбирает между WebGL и Canvas автоматически).
- parent: ID HTML-элемента, в который будет встроен холст игры.
- width и height: Размеры игрового поля.
- scene: Класс нашей сцены, которая будет запущена сразу.
Создание экземпляра new Phaser.Game(config) инициализирует движок и запускает жизненный цикл сцены.
Что попробовать дальше
Вы только что реализовали базовую, но полностью рабочую интерактивную механику рисования в Phaser. Этот паттерн — «слушать событие ввода и создавать объекты» — является фундаментальным. Для экспериментов попробуйте изменить спрайтшит на набор разных игровых предметов, добавить физические тела создаваемым объектам с помощью this.physics.add.image, чтобы они падали и сталкивались, или сохранять координаты размещенных объектов для генерации уникальных уровней. Вы также можете изменить событие с 'pointermove' на 'pointerdown', чтобы спрайты появлялись по клику, а не при движении с зажатой кнопкой.
