О чем этот пример
Работа с геометрией — мощный инструмент для создания визуальных эффектов в играх. В этом примере демонстрируется, как использовать метод `Phaser.Geom.Polygon.Clone()` для генерации потока движущихся фигур, реагирующих на действия игрока. Этот подход полезен для реализации следов, волн, частиц сложной формы или динамических фоновых анимаций без нагрузки на производительность, характерной для создания новых объектов с нуля.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
polygons;
seedPolygon;
graphics;
create ()
{
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0xaa6622 } });
this.seedPolygon = new Phaser.Geom.Polygon([
new Phaser.Math.Vector2(100, 50),
new Phaser.Math.Vector2(150, 100),
new Phaser.Math.Vector2(100, 150),
new Phaser.Math.Vector2(50, 100)
]);
this.input.on('pointermove', pointer =>
{
this.seedPolygon.points[1].x = 100 + pointer.x / 4;
this.seedPolygon.points[1].y = 50 + pointer.y / 3;
});
this.polygons = [];
}
update ()
{
this.polygons.push(Phaser.Geom.Polygon.Clone(this.seedPolygon));
this.graphics.clear();
for (let i = 0; i < this.polygons.length; i++)
{
const poly = this.polygons[i];
if (poly.points[0].x > 800)
{
this.polygons.splice(i--, 1);
continue;
}
for (let j = 0; j < poly.points.length; j++)
{
poly.points[j].x += 8 + j;
poly.points[j].y += 6 + j;
}
this.graphics.strokePoints(poly.points, true);
}
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и базового полигона
В методе create() инициализируются ключевые объекты. Создается Graphics объект для отрисовки линий, который будет использоваться в каждом кадре.
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0xaa6622 } });
Затем определяется полигон-образец (seedPolygon). Это исходная фигура, которая будет многократно клонироваться. Он создается как новый объект Phaser.Geom.Polygon, принимающий массив точек Vector2.
this.seedPolygon = new Phaser.Geom.Polygon([
new Phaser.Math.Vector2(100, 50),
new Phaser.Math.Vector2(150, 100),
new Phaser.Math.Vector2(100, 150),
new Phaser.Math.Vector2(50, 100)
]);
Слушатель события pointermove привязывает положение мыши к координатам второй точки (с индексом 1) полигона-образца. Это позволяет игроку в реальном времени деформировать исходную фигуру, перемещая указатель.
this.input.on('pointermove', pointer => {
this.seedPolygon.points[1].x = 100 + pointer.x / 4;
this.seedPolygon.points[1].y = 50 + pointer.y / 3;
});
Инициализируется пустой массив polygons, который будет хранить все клонированные полигоны.
Клонирование и анимация в update()
Метод update() выполняется каждый кадр и является сердцем анимации. Первым делом создается клон текущего состояния seedPolygon и добавляется в массив. Именно здесь применяется ключевой метод Phaser.Geom.Polygon.Clone(), который создает новый, независимый объект полигона с копией всех его точек.
this.polygons.push(Phaser.Geom.Polygon.Clone(this.seedPolygon));
Перед отрисовкой нового кадра холст очищается.
this.graphics.clear();
Затем в цикле обрабатывается каждый полигон в массиве. Проверяется условие: если первая точка полигона вышла за правую границу экрана (x > 800), этот полигон удаляется из массива. Это предотвращает бесконечный рост массива и утечку памяти.
if (poly.points[0].x > 800) {
this.polygons.splice(i--, 1);
continue;
}
Преобразование и отрисовка точек
Для создания эффекта движения и "растворения" каждая точка каждого полигона смещается. Смещение разное для каждой точки (зависит от индекса `j`), что приводит к искажению и растягиванию фигуры со временем.
for (let j = 0; j < poly.points.length; j++) {
poly.points[j].x += 8 + j;
poly.points[j].y += 6 + j;
}
Наконец, модифицированный полигон отрисовывается на холсте с помощью метода strokePoints(). Второй аргумент true указывает, что полигон замкнутый, и последняя точка будет соединена с первой.
this.graphics.strokePoints(poly.points, true);
Итог: каждый кадр создается клон-снимок текущей формы, который затем начинает жить своей жизнью — двигаться, искажаться и в итоге удаляться, создавая плавный хвост из изменяющихся фигур.
Конфигурация игры
Стандартная конфигурация игры Phaser 3. Важно, что ширина (width) установлена в 800 пикселей, что соответствует условию удаления полигонов из массива в основном цикле.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Метод Clone() — это эффективный способ тиражирования сложных геометрических объектов. В данном примере он используется для создания гипнотического эффекта шлейфа. Для экспериментов попробуйте: изменить логику смещения точек для создания вихрей или спиралей; клонировать полигон не каждый кадр, а по таймеру; привязывать к управлению игрока не одну, а несколько точек seed-полигона; вместо удаления по координате X, реализовать постепенное уменьшение непрозрачности (alpha) у graphics для каждого полигона.
