О чем этот пример
При создании игр часто возникает задача размещения объектов в пределах заданной области. Например, нужно расставить монеты внутри треугольного леса или генерировать снаряды из треугольного сектора пушки. Вручную рассчитывать координаты для таких областей сложно и неэффективно. В этой статье мы разберем, как использовать встроенные возможности геометрии Phaser для равномерной генерации случайных точек внутри треугольника, что идеально подходит для создания динамичного и разнообразного игрового пространства.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
index = 0;
points;
graphics;
triangle;
create ()
{
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0xaaaa00 }, fillStyle: { color: 0xff0000 }});
this.triangle = new Phaser.Geom.Triangle(400, 100, 100, 500, 700, 500);
this.points = [];
for (let i = 0; i < 25; i++)
{
// if we omit a parameter, new Point instance will be created and returned
this.points.push(this.triangle.getRandomPoint());
}
}
update ()
{
this.index = ++this.index % 25;
// we can also supply an instance of Point that will be modified
this.triangle.getRandomPoint(this.points[this.index]);
this.graphics.clear();
this.graphics.strokeTriangleShape(this.triangle);
for (let i = 0; i < 25; i++)
{
const p = this.points[i];
this.graphics.fillCircle(p.x, p.y, 4);
}
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание геометрической фигуры
В Phaser работа с геометрией начинается с создания объекта фигуры. В нашем примере это треугольник. Класс Phaser.Geom.Triangle принимает координаты трех вершин.
this.triangle = new Phaser.Geom.Triangle(400, 100, 100, 500, 700, 500);
Здесь мы создаем треугольник с вершинами в точках (400, 100), (100, 500) и (700, 500). Эти координаты задают его форму и расположение на сцене. Для визуализации создается объект this.graphics с заданными стилями линии и заливки, который будет рисовать фигуру.
Генерация случайных точек: два способа
Основной метод, который мы используем, — getRandomPoint(). Он принадлежит объекту треугольника и имеет две формы вызова, что является удобной идиомой в Phaser API.
Первый способ — вызвать метод без параметров. В этом случае он создаст и вернет новый объект Phaser.Geom.Point со случайными координатами внутри треугольника.
// Создание нового экземпляра точки
this.points.push(this.triangle.getRandomPoint());
Этот подход используется в цикле create() для первоначального заполнения массива this.points 25-ю точками.
Второй способ — передать методу существующий объект точки в качестве параметра. Метод модифицирует координаты `xиy` этого объекта, что более эффективно с точки зрения производительности, так как избегает создания новых объектов в памяти.
// Модификация существующего экземпляра точки
this.triangle.getRandomPoint(this.points[this.index]);
Именно этот способ используется в update() для анимации, чтобы постоянно обновлять координаты одной из точек в массиве.
Визуализация и анимация
Логика отрисовки и обновления находится в методе update(), который вызывается каждый кадр.
Сначала обновляется индекс this.index для циклического перебора массива точек. Затем координаты точки с этим индексом перезаписываются новыми случайными значениями с помощью getRandomPoint(point).
this.index = ++this.index % 25;
this.triangle.getRandomPoint(this.points[this.index]);
Перед каждой отрисовкой Graphics очищается методом clear(). После этого отрисовывается контур треугольника и все 25 точек в виде закрашенных кругов.
this.graphics.clear();
this.graphics.strokeTriangleShape(this.triangle);
for (let i = 0; i < 25; i++)
{
const p = this.points[i];
this.graphics.fillCircle(p.x, p.y, 4);
}
В результате мы видим статичный треугольник, внутри которого одна из 25 точек постоянно "телепортируется" в новую случайную позицию, создавая эффект мерцания.
Практическое применение в играх
Этот механизм — не просто демонстрация математики, а готовый инструмент для геймдизайна.
* **Спавн предметов:** Равномерно заполнить треугольную область ресурсами, ловушками или бонусами. * **Зона поражения:** Если треугольник задает конус атаки магии или прожектора, точки могут отмечать попадания. * **Партиклы:** Задать треугольную область эмиттера для системы частиц, чтобы дым или искры вылетали из конкретного сектора.
Ключевое преимущество — равномерное распределение. Метод getRandomPoint() гарантирует, что у точки одинаковая вероятность оказаться в любой части площади треугольника, а не только около центра. Это делает размещение объектов естественным.
Что попробовать дальше
Использование Phaser.Geom.Triangle.getRandomPoint() — это элегантный и производительный способ работы со случайностью внутри сложных областей. Он избавляет от необходимости писать собственные алгоритмы выборки. Для экспериментов попробуйте изменить форму треугольника в реальном времени в ответ на действия игрока, комбинировать несколько треугольников для создания сложных полигонов или привязать генерацию точек к таймеру для создания волн противников, выходящих из треугольного портала.
