О чем этот пример
В игровом движке Phaser геометрические объекты — это не просто фигуры для отрисовки. Они предоставляют мощные методы для вычислений и управления объектами. Один из таких методов — `getPoint()` для треугольников. Эта статья покажет, как с его помощью заставить объект плавно перемещаться по периметру треугольника, что открывает возможности для создания патрульных маршрутов, траекторий снарядов или UI-элементов со сложным движением. Мы разберем практический пример, где точка (представленная прямоугольником) циклично "скользит" по сторонам треугольника. Вы поймете, как работает интерполяция позиции, как управлять скоростью движения и как визуализировать этот процесс.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
a = 0;
point;
triangle;
graphics;
create ()
{
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});
// triangle = new Phaser.Geom.Triangle.BuildEquilateral(400, 200, 300);
// triangle = new Phaser.Geom.Triangle.BuildRight(200, 400, 300, 200);
// Random
const x1 = Phaser.Math.Between(50, 400);
const y1 = Phaser.Math.Between(50, 300);
const x2 = Phaser.Math.Between(450, 750);
const y2 = Phaser.Math.Between(50, 300);
const x3 = Phaser.Math.Between(50, 750);
const y3 = Phaser.Math.Between(350, 550);
this.triangle = new Phaser.Geom.Triangle(x1, y1, x2, y2, x3, y3);
this.point = new Phaser.Geom.Rectangle(0, 0, 16, 16);
}
update ()
{
this.a += 0.005;
if (this.a > 1)
{
this.a = 0;
}
this.triangle.getPoint(this.a, this.point);
this.graphics.clear();
this.graphics.lineStyle(2, 0x00ff00);
this.graphics.strokeTriangleShape(this.triangle);
this.graphics.fillStyle(0xff00ff);
this.graphics.fillRect(this.point.x - 8, this.point.y - 8, this.point.width, this.point.height);
}
}
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: 0x00ff00 }, fillStyle: { color: 0xff0000 }});
Затем, в примере используется один из трех вариантов создания треугольника. Комментированные строки показывают, как можно создать равносторонний или прямоугольный треугольник, но активным остается вариант со случайными координатами.
// Random
const x1 = Phaser.Math.Between(50, 400);
const y1 = Phaser.Math.Between(50, 300);
const x2 = Phaser.Math.Between(450, 750);
const y2 = Phaser.Math.Between(50, 300);
const x3 = Phaser.Math.Between(50, 750);
const y3 = Phaser.Math.Between(350, 550);
this.triangle = new Phaser.Geom.Triangle(x1, y1, x2, y2, x3, y3);
Важно: this.triangle — это объект данных (Phaser.Geom.Triangle), хранящий только координаты вершин. Он не отрисовывается сам по себе.
Также создается объект точки. Для удобства отрисовки и работы с методом getPoint(), точка представлена не простым объектом {x, y}, а прямоугольником Phaser.Geom.Rectangle. Это позволяет хранить не только позицию (x, y), но и размеры (width, height), что пригодится позже для центрирования графики.
this.point = new Phaser.Geom.Rectangle(0, 0, 16, 16);
Магия метода getPoint() и интерполяции
Сердце анимации бьется в методе update(). Ключевую роль играет метод Phaser.Geom.Triangle.getPoint(position, output). Его задача — вычислить точку на периметре треугольника на основе параметра position.
- position (число от 0 до 1): Определяет, где на контуре находится точка. 0 соответствует первой вершине (x1, y1). При увеличении значения точка движется по сторонам треугольника. Значение 1 снова возвращает нас к первой вершине, замыкая круг.
- output (объект): Любой объект со свойствами `xиy(например,Phaser.Geom.Rectangle,Phaser.Math.Vector2или обычный{x:0, y:0}`). Метод запишет в него вычисленные координаты.
В коде значение position хранится в переменной this.a. Каждый кадр оно увеличивается на небольшую величину.
this.a += 0.005;
if (this.a > 1)
{
this.a = 0;
}
Затем вызывается сам метод, который модифицирует переданный ему прямоугольник this.point, обновляя его свойства `xиy`.
this.triangle.getPoint(this.a, this.point);
Теперь this.point.x и this.point.y содержат актуальные координаты на стороне треугольника. Изменяя шаг приращения (0.005), вы контролируете скорость движения точки по контуру.
Визуализация: Отрисовка кадра за кадром
После вычисления новой позиции точки, сцена перерисовывается. Первым делом очищается canvas от графики предыдущего кадра.
this.graphics.clear();
Затем задается стиль линии и рисуется контур треугольника. Обратите внимание на использование strokeTriangleShape(), который принимает объект геометрии this.triangle.
this.graphics.lineStyle(2, 0x00ff00);
this.graphics.strokeTriangleShape(this.triangle);
Наконец, отрисовывается движущаяся точка. Поскольку this.point — это прямоугольник с центром в вычисленных координатах, для его отрисовки в виде квадрата мы используем fillRect(). Координаты для отрисовки (this.point.x - 8, this.point.y - 8) смещены на половину ширины и высоты, чтобы квадрат был центрирован относительно линии контура.
this.graphics.fillStyle(0xff00ff);
this.graphics.fillRect(this.point.x - 8, this.point.y - 8, this.point.width, this.point.height);
Этот цикл (вычисление -> очистка -> рисование) повторяется каждый кадр, создавая иллюзию плавного движения.
Практическое применение и вариации
Рассмотренный принцип универсален. Вместо прямоугольника по контуру может двигаться спрайт врага, создавая патрульный маршрут.
// В create()
this.sprite = this.physics.add.sprite(0, 0, 'enemy');
// В update()
this.triangle.getPoint(this.a, this.sprite);
Можно использовать несколько точек с разной скоростью (разным шагом this.a) для создания сложных эффектов. Метод getPoint() работает и с другими геометрическими объектами, например, Phaser.Geom.Line.getPoint() или Phaser.Geom.Circle.getPoint(), открывая путь для движения по любым траекториям.
Важно помнить: метод возвращает точку именно на *периметре* фигуры. Для получения точки внутри треугольника (интерполяции по площади) потребуются другие методы или ручные вычисления.
Что попробовать дальше
Метод Phaser.Geom.Triangle.getPoint() — это элегантный инструмент для работы с линейной интерполяцией вдоль контура. Он абстрагирует сложные математические вычисления, позволяя сосредоточиться на игровой логике. Для экспериментов попробуйте
- Привязать к точке спрайт с физическим телом
- Создать массив из нескольких треугольников и заставить объект переходить с одного на другой
- Использовать
Phaser.Geom.Triangle.GetPoints()для получения сразу нескольких точек на контуре и создать, например, эффект "бегущих огней" по границе зоны
