О чем этот пример
Создание динамичных визуальных эффектов, распределение объектов по локации или реализация стохастического поведения врагов — всё это часто требует умения генерировать случайные позиции в пределах заданной области. Встроенный геометрический модуль Phaser предоставляет для этого элегантные инструменты. В этой статье мы разберём, как использовать класс `Phaser.Geom.Circle` и его метод `getRandomPoint()` для заполнения круговой области случайными точками. Этот подход универсален и может быть применён для создания частиц дыма, разброса предметов или случайного патрулирования.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
index = 0;
points;
graphics;
circle;
create ()
{
this.circle = new Phaser.Geom.Circle(400, 300, 250);
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});
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.circle.getRandomPoint());
}
}
update ()
{
this.index = ++this.index % 25;
// we can also supply an instance of Point that will be modified
this.circle.getRandomPoint(this.points[this.index]);
this.graphics.clear();
this.graphics.strokeCircleShape(this.circle);
for (let i = 0; i < 25; i++)
{
const p = this.points[i];
this.graphics.fillRect(p.x - 4, p.y - 4, 8, 8);
}
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание геометрической фигуры и подготовка сцены
Вся работа начинается с создания экземпляра круга. Класс Phaser.Geom.Circle принимает три параметра: координаты центра по осям X и Y, а также радиус.
Также мы инициализируем объект Graphics для отрисовки и массив для хранения сгенерированных точек.
this.circle = new Phaser.Geom.Circle(400, 300, 250);
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});
this.points = [];
Два способа использования getRandomPoint()
Метод circle.getRandomPoint() — это сердце нашего примера. Он обладает важной особенностью: его можно вызывать двумя способами.
**Способ 1: Создание нового объекта.** Если вызвать метод без аргументов, он создаст и вернёт новый экземпляр Phaser.Geom.Point со случайными координатами внутри круга. Этот способ удобен для первоначального заполнения массива.
// Создаётся новый Point и добавляется в массив
this.points.push(this.circle.getRandomPoint());
**Способ 2: Модификация существующего объекта.** Если передать методу существующий объект Point в качестве аргумента, метод не будет создавать новый объект, а изменит координаты переданного. Это эффективно с точки зрения производительности, так как избегает лишних операций создания объектов (аллокаций) в основном игровом цикле update.
// Координаты существующего объекта points[index] будут перезаписаны
this.circle.getRandomPoint(this.points[this.index]);
Динамическое обновление и отрисовка
В методе update() реализована анимация: на каждом кадре одна из точек в массиве обновляется на новую случайную позицию внутри того же круга. После этого вся графика очищается и перерисовывается.
Ключевые шаги:
1. Выбор индекса точки для обновления.
2. Модификация её координат через getRandomPoint(point).
3. Очистка холста Graphics.
4. Отрисовка контура круга и всех точек в виде маленьких квадратов.
update ()
{
// Циклическое увеличение индекса от 0 до 24
this.index = ++this.index % 25;
// Эффективное обновление координат уже существующей точки
this.circle.getRandomPoint(this.points[this.index]);
this.graphics.clear();
// Рисуем контур (stroke) круга
this.graphics.strokeCircleShape(this.circle);
// Рисуем все точки как залитые (fill) прямоугольники
for (let i = 0; i < 25; i++)
{
const p = this.points[i];
this.graphics.fillRect(p.x - 4, p.y - 4, 8, 8);
}
}
Конфигурация и запуск игры
Финальный шаг — стандартная для Phaser конфигурация игры, в которой указывается наша сцена Example.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example // Указываем наш класс сцены
};
const game = new Phaser.Game(config);
Что попробовать дальше
Метод getRandomPoint() класса Phaser.Geom.Circle — это мощный и гибкий инструмент для работы со случайными позициями. Его двойной режим работы (создание или модификация объекта) позволяет оптимизировать код в зависимости от контекста: инициализация или постоянное обновление.
**Идеи для экспериментов:**
1. Замените круг на Phaser.Geom.Rectangle и используйте его метод getRandomPoint().
2. Создайте несколько кругов с разными радиусами и генерируйте точки внутри них, чтобы создать сложную зону спавна.
3. Вместо статичного круга сделайте его радиус или положение зависимыми от времени или действий игрока, чтобы точки динамически следовали за изменяющейся областью.
4. Используйте точки как цели для снарядов или позиции для появления мобов в круговой арене.
