О чем этот пример
При создании игр часто приходится работать с большими группами объектов — врагами, бонусами, частицами. Искать среди них нужный по определенным критериям вручную через циклы утомительно и неэффективно. Класс `Phaser.Actions` в Phaser 3 предлагает простое и мощное решение. В этой статье разберем, как с помощью метода `Phaser.Actions.GetFirst` быстро найти первый спрайт в массиве, который соответствует вашим условиям, и мгновенно отреагировать на него анимацией. Этот подход делает код чище, а логику игровых механик — более выразительной.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.spritesheet('diamonds', 'assets/sprites/diamonds32x5.png', { frameWidth: 64, frameHeight: 64 });
}
create ()
{
const gems = [];
for (let i = 1; i < 64; i++)
{
const x = Phaser.Math.Between(100, 700);
const y = Phaser.Math.Between(100, 500);
const frame = Phaser.Math.Between(0, 4);
gems.push(this.add.sprite(x, y, 'diamonds', frame));
}
this.add.text(16, 16, 'Click to find the first Red gem with a Scale of 1');
const redFrame = this.textures.getFrame('diamonds', 0);
this.input.on('pointerdown', () => {
// Get the first sprite with a scale of 1 that is using the Red frame
const red = Phaser.Actions.GetFirst(gems, { scaleX: 1, frame: redFrame });
if (red)
{
this.children.bringToTop(red);
this.tweens.chain({
targets: red,
tweens: [
{
scale: 2,
duration: 400,
ease: 'Bounce.easeOut'
},
{
delay: 500,
scale: 0,
duration: 1000
}
]
});
}
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены: создание массива спрайтов
В примере создается сцена, которая в методе preload загружает спрайтшит с алмазами. Ключевой этап происходит в create. Здесь мы создаем массив gems и в цикле заполняем его 63 спрайтами. Каждому спрайту случайным образом задаются координаты (`x,y) и кадр анимации (frame`) от 0 до 4.
const gems = [];
for (let i = 1; i < 64; i++) {
const x = Phaser.Math.Between(100, 700);
const y = Phaser.Math.Between(100, 500);
const frame = Phaser.Math.Between(0, 4);
gems.push(this.add.sprite(x, y, 'diamonds', frame));
}
Таким образом, мы получаем игровое поле, усыпанное разноцветными камнями в случайных местах. Массив gems становится нашей коллекцией для поиска.
Условия поиска: как задать критерии для GetFirst
Метод Phaser.Actions.GetFirst принимает два аргумента: массив элементов и объект с критериями поиска. В примере мы хотим найти первый красный алмаз (кадр 0), который еще не был масштабирован (имеет scaleX: 1).
Сначала мы получаем ссылку на нужный кадр из текстуры:
const redFrame = this.textures.getFrame('diamonds', 0);
Затем, по клику мыши, запускаем поиск:
const red = Phaser.Actions.GetFirst(gems, { scaleX: 1, frame: redFrame });
Метод переберет массив gems и вернет первый спрайт, у которого одновременно scaleX равен 1 и свойство frame строго равно объекту redFrame. Если такого спрайта нет, вернется undefined. Это гораздо удобнее ручного перебора с условиями if.
Реакция на результат: анимация и управление отображением
После того как объект найден, мы можем с ним взаимодействовать. В примере найденный красный алмаз визуально выделяется.
Сначала он перемещается на передний план с помощью метода this.children.bringToTop(). Это гарантирует, что его анимация не будет перекрыта другими спрайтами.
if (red) {
this.children.bringToTop(red);
}
Затем для объекта запускается цепочка твинов (tweens.chain). Сначала алмаз увеличивается до двойного размера с "пружинящей" анимацией (Bounce.easeOut), а после небольшой задержки плавно исчезает, уменьшаясь до нуля.
this.tweens.chain({
targets: red,
tweens: [
{ scale: 2, duration: 400, ease: 'Bounce.easeOut' },
{ delay: 500, scale: 0, duration: 1000 }
]
});
Эта простая последовательность делает взаимодействие с объектом отзывчивым и приятным для игрока.
Гибкость критериев: что еще можно искать
Сила Phaser.Actions.GetFirst в гибкости объекта критериев. Вы можете искать объекты по любым числовым, строковым или булевым свойствам, которые у них есть. Например:
* По положению: `{ x: 400, y: 300 }`
* По видимости: `{ visible: true }`
* По здоровью или другим игровым параметрам, если вы их добавили: `{ hp: 100 }`
* По комбинации свойств: `{ scaleY: 0.5, alpha: 1 }`
Важно понимать, что сравнение идет по строгому равенству (===). Для поиска по диапазону значений (например, x > 100) этот метод не подойдет — здесь придется использовать Phaser.Actions.Call или обычный цикл. GetFirst идеален для точного, дискретного поиска.
Что попробовать дальше
Phaser.Actions.GetFirst — это элегантный инструмент для декларативного поиска объектов в массиве. Он избавляет от написания шаблонных циклов, делает код нагляднее и концентрирует внимание на условиях поиска, а не на механике перебора. Для экспериментов попробуйте: изменить критерии поиска на { scaleX: 1, frame: 2 } для поиска синего алмаза; добавить проверку на свойство alpha; или использовать найденный объект не для анимации, а для начисления очков или запуска игрового события.
