О чем этот пример
В разработке игр часто возникает задача заставить объект двигаться по чёткой траектории — например, патрулировать вдоль стены или облетать здание по контуру. Вручную рассчитывать такие пути может быть утомительно. К счастью, Phaser предоставляет элегантное решение. В этой статье мы разберем, как использовать метод `Phaser.Geom.Rectangle.PerimeterPoint` для плавного перемещения точки по периметру любого прямоугольника. Этот приём полезен для создания циклических анимаций, траекторий врагов или визуальных эффектов, связанных с границами области.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
a = 0;
point;
rect;
graphics;
create ()
{
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});
this.rect = new Phaser.Geom.Rectangle(32, 32, 256, 256);
this.point = new Phaser.Geom.Rectangle(0, 0, 8, 8);
}
update ()
{
this.a++;
Phaser.Geom.Rectangle.PerimeterPoint(this.rect, this.a, this.point);
this.graphics.clear();
this.graphics.strokeRectShape(this.rect);
this.graphics.fillRect(this.point.x - 4, this.point.y - 4, this.point.width, this.point.height);
// Draw a line from the center of the rect to the point on the perimeter
this.graphics.lineStyle(2, 0xffffff);
this.graphics.beginPath();
this.graphics.moveTo(this.rect.centerX, this.rect.centerY);
this.graphics.lineTo(this.point.x, this.point.y);
this.graphics.closePath();
this.graphics.strokePath();
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и геометрических объектов
Вся логика примера размещена внутри класса сцены, унаследованного от Phaser.Scene. Для визуализации нам понадобятся объекты Graphics, прямоугольник и точка.
class Example extends Phaser.Scene
{
a = 0;
point;
rect;
graphics;
В методе create() мы инициализируем эти объекты. this.graphics — это наш холст для рисования. this.rect — основной прямоугольник, по периметру которого будет двигаться точка. Обратите внимание, что this.point также создаётся как объект Phaser.Geom.Rectangle. Это небольшой прямоугольник (8x8 пикселей), который будет служить визуальным маркером позиции на периметре.
create ()
{
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});
this.rect = new Phaser.Geom.Rectangle(32, 32, 256, 256);
this.point = new Phaser.Geom.Rectangle(0, 0, 8, 8);
}
Сердце примера: метод PerimeterPoint
Вся магия происходит в методе update(), который вызывается на каждом кадре. Ключевая строка — вызов Phaser.Geom.Rectangle.PerimeterPoint().
update ()
{
this.a++;
Phaser.Geom.Rectangle.PerimeterPoint(this.rect, this.a, this.point);
Этот метод выполняет следующее:
1. **Принимает прямоугольник (`this.rect`)** — область, периметр которой мы используем.
2. **Принимает угол или позицию (`this.a`)**. В данном примере `this.a` — это просто увеличивающееся на 1 каждый кадр число. Метод интерпретирует его как позицию на периметре. Весь периметр условно «растянут» в линию, и `this.a` указывает точку на этой линии. Когда значение превышает общую длину периметра (которая равна `2 * (ширина + высота)`), оно зацикливается, обеспечивая непрерывное движение.
3. **Записывает результат в объект `this.point`**. Координаты `x` и `y` переданного прямоугольника `this.point` обновляются, указывая на рассчитанную позицию на периметре. Важно: исходные `width` и `height` объекта `this.point` (8x8) не изменяются, меняются только его координаты.
Таким образом, каждый кадр наша «точка» (маленький красный квадрат) перемещается на новую позицию вдоль границы зеленого прямоугольника.
Визуализация: отчистка, рисование и линии
После расчёта новой позиции точки мы обновляем графику.
this.graphics.clear();
this.graphics.strokeRectShape(this.rect);
this.graphics.fillRect(this.point.x - 4, this.point.y - 4, this.point.width, this.point.height);
1. `this.graphics.clear()` — стирает всё, нарисованное в предыдущем кадре.
2. `this.graphics.strokeRectShape(this.rect)` — заново рисует контур (stroke) основного зеленого прямоугольника.
3. `this.graphics.fillRect(...)` — рисует закрашенный красный квадрат в качестве маркера. Мы центрируем его относительно рассчитанной точки, вычитая половину его ширины и высоты (4 пикселя) из координат `this.point.x` и `this.point.y`.
Для наглядности также рисуется белая линия из центра основного прямоугольника к текущей позиции точки на периметре.
this.graphics.lineStyle(2, 0xffffff);
this.graphics.beginPath();
this.graphics.moveTo(this.rect.centerX, this.rect.centerY);
this.graphics.lineTo(this.point.x, this.point.y);
this.graphics.closePath();
this.graphics.strokePath();
Использование this.rect.centerX и this.rect.centerY — это удобное свойство объекта Phaser.Geom.Rectangle, которое избавляет от необходимости вычислять центр вручную.
Конфигурация и запуск игры
Пример завершается стандартной для Phaser 3 конфигурацией игры.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Эта конфигурация создаёт игровое окно размером 800x600 пикселей, автоматически выбирает рендерер (WebGL или Canvas) и указывает, что класс Example является стартовой сценой.
Что попробовать дальше
Метод PerimeterPoint — это мощный и простой инструмент для работы с траекториями движения вдоль прямоугольных границ. Он избавляет разработчика от сложных тригонометрических расчётов. Для экспериментов попробуйте:
1. Изменить скорость движения, увеличивая this.a не на 1, а на другое значение (например, this.a += 0.5 для замедления).
2. Привязать к движущейся точке спрайт врага или полезного предмета, создав патрулирующего сторожа.
3. Использовать позицию точки для генерации частиц (this.add.particles) на границах экрана, создавая эффект мерцающего контура.
4. Применить тот же принцип к Phaser.Geom.Triangle, у которого также есть метод PerimeterPoint.
