О чем этот пример
В игровом движке Phaser управление множеством объектов одновременно — частая задача. В этом примере мы рассмотрим, как заставить группу спрайтов плавно следовать за указателем мыши, используя встроенный хелпер `Phaser.Actions.ShiftPosition`. Этот подход эффективен для создания эффектов "роя", визуальных следов или интерактивных скоплений частиц без необходимости вручную обновлять позицию каждого объекта.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
this.move = 0;
this.x = 0;
this.y = 0;
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('sky', 'assets/skies/deepblue.png');
this.load.image('ball', 'assets/demoscene/ball-tlb.png');
}
create ()
{
this.add.image(0, 0, 'sky')
.setOrigin(0);
this.group = this.add.group({ key: 'ball', frameQuantity: 128 });
this.input.on('pointermove', function (pointer) {
this.x = pointer.x;
this.y = pointer.y;
}, this);
}
update (time, delta)
{
this.move += delta;
if (this.move > 6)
{
Phaser.Actions.ShiftPosition(this.group.getChildren(), this.x, this.y);
this.move = 0;
}
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Инициализация сцены и переменных состояния
В конструкторе класса сцены Example мы инициализируем три важные переменные. Переменная this.move будет служить таймером для контроля частоты обновления позиций объектов. Переменные this.x и this.y будут хранить последние известные координаты курсора мыши.
constructor ()
{
super();
this.move = 0;
this.x = 0;
this.y = 0;
}
Создание группы объектов и подписка на движение мыши
В методе create мы сначала добавляем фоновое изображение. Затем создаем группу (this.add.group) из 128 идентичных спрайтов с ключом 'ball'. Группа в Phaser — это мощный инструмент для управления коллекциями игровых объектов.
Затем мы настраиваем обработчик события pointermove. При каждом движении мыши он обновляет внутренние переменные this.x и this.y, записывая в них текущие координаты курсора. Обратите внимание на третий аргумент this в вызове this.input.on, который определяет контекст выполнения функции-обработчика.
create ()
{
this.add.image(0, 0, 'sky')
.setOrigin(0);
this.group = this.add.group({ key: 'ball', frameQuantity: 128 });
this.input.on('pointermove', function (pointer) {
this.x = pointer.x;
this.y = pointer.y;
}, this);
}
Основной игровой цикл и применение ShiftPosition
Метод update выполняется каждый кадр игры. Параметр delta представляет время, прошедшее с предыдущего кадра, в миллисекундах. Мы накапливаем это время в переменной this.move.
Когда накопленное время превышает порог в 6 миллисекунд, срабатывает основная логика. Мы вызываем Phaser.Actions.ShiftPosition. Первым аргументом передаем массив детей группы, полученный через this.group.getChildren(). Второй и третий аргументы — целевые координаты this.x и this.y. После выполнения действия сбрасываем таймер this.move в ноль.
update (time, delta)
{
this.move += delta;
if (this.move > 6)
{
Phaser.Actions.ShiftPosition(this.group.getChildren(), this.x, this.y);
this.move = 0;
}
}
Функция ShiftPosition циклически сдвигает позицию каждого объекта в массиве: позиция первого объекта становится равной целевой точке, позиция второго объекта становится равной предыдущей позиции первого, и так далее. Это создает эффект плавной цепочки или "змейки" из объектов, следующих за целью.
Настройка и запуск игры
Конфигурационный объект config определяет основные параметры игры, такие как тип рендерера, размеры холста и основную сцену. Затем создается экземпляр игры new Phaser.Game(config), который запускает весь процесс.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Использование Phaser.Actions.ShiftPosition — это отличный способ анимировать группу объектов с минимальным кодом. Для экспериментов попробуйте изменить порог в условии this.move > 6 — это повлияет на скорость реакции "роя". Также можно модифицировать логику, чтобы цель следовала не за курсором, а за другим игровым объектом, или применить другие методы из модуля Phaser.Actions, например Rotate или Scale, для создания более сложных визуальных эффектов.
