О чем этот пример
В создании игр часто возникает задача анимировать группу объектов по сложной траектории, например, заставить частицы вращаться вокруг центра. Прописывать такую логику для каждого спрайта вручную — долго и неэффективно. В этом примере мы рассмотрим мощный и элегантный инструмент Phaser — `Phaser.Actions.RotateAroundDistance`. Этот метод позволяет одним вызовом применить вращение с заданным радиусом ко всем элементам массива или группы, что идеально подходит для создания визуальных эффектов, орбит планет или вращающихся щитов.
Версия 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.image('ball', 'assets/sprites/shinyball.png');
}
create ()
{
this.group = this.add.group();
for (let i = 0; i < 32; i++)
{
this.group.create(i * 32, i * 2, 'ball');
}
}
update ()
{
Phaser.Actions.RotateAroundDistance(this.group.getChildren(), { x: 400, y: 300 }, 0.02, 200);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и создание группы
Вся логика примера содержится в классе сцены Example. В методе preload() загружается один спрайт — изображение шарика (shinyball.png).
Ключевой объект для нашего эффекта — группа (Group). Группы в Phaser отлично подходят для управления коллекциями похожих объектов. В методе create() мы создаем группу this.group и наполняем ее 32 спрайтами шарика, располагая их по диагонали. Каждый следующий шарик смещается на 32 пикселя по X и на 2 пикселя по Y относительно предыдущего.
this.group = this.add.group();
for (let i = 0; i < 32; i++)
{
this.group.create(i * 32, i * 2, 'ball');
}
Применение RotateAroundDistance
Вся анимация происходит в методе update(), который вызывается на каждом кадре игры. Именно здесь используется статический метод Phaser.Actions.RotateAroundDistance().
Метод принимает четыре аргумента:
1. **Массив объектов:** В нашем случае это список всех детей группы, полученный через `this.group.getChildren()`.
2. **Точка вращения:** Объект с координатами `{ x: 400, y: 300 }`. Это центр, вокруг которого будут вращаться все шарики.
3. **Угол:** Значение `0.02`. Это угол (в радианах), на который каждый объект будет поворачиваться вокруг центра за один кадр. Положительное значение задает вращение против часовой стрелки.
4. **Расстояние:** Значение `200`. Это фиксированный радиус (дистанция) от центра вращения до каждого объекта.
Phaser.Actions.RotateAroundDistance(this.group.getChildren(), { x: 400, y: 300 }, 0.02, 200);
На каждом кадре метод пересчитывает позицию каждого шарика из переданного массива, размещая его на окружности с радиусом 200 пикселей вокруг точки (400, 300), и добавляет небольшой угловой сдвиг.
Как это работает внутри
Важно понимать, что RotateAroundDistance не меняет изначальное расстояние объектов от центра. Вместо этого он использует переданный параметр distance как целевой радиус для всех объектов. Изначальная диагональная линия из шариков мгновенно "схлопывается" в круглую формацию при первом же вызове в update().
Метод работает по принципу:
1. Для каждого объекта вычисляется текущий угол между ним и центром вращения.
2. К этому углу прибавляется значение angle (0.02 радиана).
3. Новая позиция объекта вычисляется по формуле тригонометрии для окружности: x = centerX + distance * cos(newAngle), y = centerY + distance * sin(newAngle).
4. Координаты объекта напрямую присваиваются этим новым значениям.
Это доказывает, что исходное взаимное расположение шариков (диагональ) не имеет значения для итоговой анимации — все они будут вращаться по одной и той же окружности.
Конфигурация игры
Сцена включается в игру через стандартную конфигурацию. Указывается тип рендерера (Phaser.AUTO), размеры холста, цвет фона и ID родительского HTML-элемента.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Phaser.Actions.RotateAroundDistance — это мощный и лаконичный инструмент для создания сложных циклических движений. Всего одна строка кода в update() заменяет десятки строк ручных вычислений. Для экспериментов попробуйте изменить параметры: сделайте угол вращения зависимым от времени (this.time.now * 0.001), чтобы управлять скоростью, или динамически меняйте distance для создания эффекта пульсирующей орбиты. Можно применить этот метод не ко всей группе, а к отфильтрованному массиву объектов, создавая несколько независимых вращающихся систем.
