О чем этот пример
В игровой разработке часто требуется работать не только с графическим представлением объектов, но и с их ограничивающими областями для проверки столкновений, отрисовки UI или оптимизации. В Phaser для геометрических примитивов, таких как эллипс, есть удобный метод `GetBounds`. Эта статья на практическом примере покажет, как получить прямоугольную область (bounds), которая полностью содержит эллипс, и как динамически её пересчитывать при изменении формы и положения фигуры. Это полезно для визуальной отладки столкновений и понимания реальных размеров объектов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
a = 0;
graphics;
bounds;
ellipse;
create ()
{
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x0000aa }, fillStyle: { color: 0x00aaaa }});
this.ellipse = new Phaser.Geom.Ellipse(400, 300, 250, 150);
// if we omit the out parameter, we get a new Rectangle instance
this.bounds = Phaser.Geom.Ellipse.GetBounds(this.ellipse);
}
update ()
{
this.a += 0.01;
if (this.a > Math.PI * 4)
{
this.a -= Math.PI * 4;
}
this.ellipse.x = 400 - Math.cos(this.a / 2) * 300;
this.ellipse.y = 300 - Math.sin(this.a * 2) * 200;
this.ellipse.width = Math.sin(this.a) * Math.sin(this.a) * 300;
this.ellipse.height = Math.cos(this.a) * Math.sin(this.a) * 300;
// or we can supply a Rectangle instance to modify
Phaser.Geom.Ellipse.GetBounds(this.ellipse, this.bounds);
this.graphics.clear();
this.graphics.fillEllipseShape(this.ellipse);
this.graphics.strokeRectShape(this.bounds);
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Инициализация сцены и создание эллипса
В классе сцены Example объявлены свойства для хранения графического контекста, самого эллипса и его ограничивающего прямоугольника. В методе create() происходит базовая настройка.
Сначала создаётся объект Graphics для рисования линий и заливки. Затем создаётся экземпляр Phaser.Geom.Ellipse. Его конструктор принимает координаты центра (x, y) и два радиуса (width, height).
this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x0000aa }, fillStyle: { color: 0x00aaaa }});
this.ellipse = new Phaser.Geom.Ellipse(400, 300, 250, 150);
Важный момент — первое получение границ. Статический метод Phaser.Geom.Ellipse.GetBounds можно вызвать двумя способами. Если передать только эллипс, метод вернёт новый экземпляр Phaser.Geom.Rectangle.
this.bounds = Phaser.Geom.Ellipse.GetBounds(this.ellipse);
Динамическое изменение параметров эллипса
Логика анимации вынесена в метод update(), который выполняется каждый кадр. Угол `aпостоянно увеличивается, изменяя параметры эллипса: его положение (x,y) и размеры (width,height`).
this.a += 0.01;
if (this.a > Math.PI * 4)
{
this.a -= Math.PI * 4;
}
this.ellipse.x = 400 - Math.cos(this.a / 2) * 300;
this.ellipse.y = 300 - Math.sin(this.a * 2) * 200;
this.ellipse.width = Math.sin(this.a) * Math.sin(this.a) * 300;
this.ellipse.height = Math.cos(this.a) * Math.sin(this.a) * 300;
Эти формулы создают сложное движение: центр эллипса движется по траектории Лиссажу, а размеры пульсируют по синусоидальным законам. После каждого изменения параметров эллипса необходимо пересчитать его ограничивающий прямоугольник.
Получение и использование ограничивающего прямоугольника
После обновления свойств эллипса вызывается метод GetBounds во второй раз. Здесь демонстрируется его вторая форма вызова — с передачей второго аргумента out. В этот аргумент нужно передать существующий объект Phaser.Geom.Rectangle, который будет изменён (модифицирован) новыми значениями. Это эффективно с точки зрения производительности, так как не создаёт новый объект каждый кадр.
Phaser.Geom.Ellipse.GetBounds(this.ellipse, this.bounds);
Затем graphics очищается, и происходит отрисовка. Сначала заливается сам эллипс, а поверх него рисуется контур его ограничивающего прямоугольника.
this.graphics.clear();
this.graphics.fillEllipseShape(this.ellipse);
this.graphics.strokeRectShape(this.bounds);
Визуально это позволяет наблюдать, как прямоугольная область точно охватывает эллипс при любых его деформациях и перемещениях.
Конфигурация и запуск игры
Код завершается стандартной для Phaser конфигурацией игры. В объекте config задаётся размер холста, тип рендерера, родительский HTML-элемент и основной класс сцены.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Именно эта конфигурация создаёт экземпляр игры, который запускает жизненный цикл сцены (create, update).
Что попробовать дальше
Метод Phaser.Geom.Ellipse.GetBounds — это ключевой инструмент для работы с пространственными границами эллипса. Его использование в двух формах (с созданием нового объекта или модификацией существующего) даёт гибкость для оптимизации. Для экспериментов попробуйте
- Использовать
this.boundsдля простой проверки пересечения с другими прямоугольниками - Привязать изменение размеров эллипса к игровому времени
- Нарисовать несколько эллипсов с их bounds и реализовать отладочный режим их визуализации по нажатию клавиши
