О чем этот пример
В разработке игр точное позиционирование объектов — это залог стабильной физики, корректных коллизий и чистого визуального отображения. Особенно это критично при работе с пиксель-арт графикой или привязке объектов к сетке. В этом примере мы рассмотрим, как метод `Phaser.Geom.Rectangle.Floor()` помогает избавиться от "дрожания" и артефактов, округляя координаты прямоугольника до целых чисел. Метод `floor` (пол) — это математическая операция округления в меньшую сторону. Применяя её к координатам геометрической фигуры, мы гарантируем, что её положение на экране будет целочисленным, что часто необходимо для точного рендеринга. Визуальный пример наглядно демонстрирует разницу между обычным движением и движением с принудительным округлением.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
y = 0;
graphics;
rect2;
rect1;
create ()
{
this.graphics = this.add.graphics({ fillStyle: { color: 0x0000aa } });
this.rect1 = new Phaser.Geom.Rectangle(100, 0, 250, 100);
this.rect2 = new Phaser.Geom.Rectangle(450, 0, 250, 100);
}
update ()
{
this.y += 0.05;
this.rect1.y = this.rect2.y = this.y;
Phaser.Geom.Rectangle.Floor(this.rect2);
this.graphics.clear();
this.graphics.fillRectShape(this.rect1);
this.graphics.fillRectShape(this.rect2);
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и создание объектов
В начале кода мы создаём класс сцены и объявляем необходимые переменные. Обратите внимание, что rect1 и rect2 будут хранить объекты прямоугольников, а graphics — это холст для их отрисовки.
class Example extends Phaser.Scene
{
y = 0;
graphics;
rect2;
rect1;
В методе create() инициализируются графический объект и два прямоугольника с помощью конструктора Phaser.Geom.Rectangle. Каждому задаётся начальная позиция `x,yи размерыwidth,height. Оба прямоугольника стартуют сy = 0`, но на разных горизонтальных позициях.
create ()
{
this.graphics = this.add.graphics({ fillStyle: { color: 0x0000aa } });
this.rect1 = new Phaser.Geom.Rectangle(100, 0, 250, 100);
this.rect2 = new Phaser.Geom.Rectangle(450, 0, 250, 100);
}
Анимация и применение метода Floor
Сердцевина примера находится в методе update(), который вызывается каждый кадр. Здесь происходит движение прямоугольников вниз и ключевое действие — округление координат для одного из них.
update ()
{
this.y += 0.05;
this.rect1.y = this.rect2.y = this.y;
Phaser.Geom.Rectangle.Floor(this.rect2);
1. Переменная this.y увеличивается на небольшое значение (0.05) каждый кадр, создавая плавное движение.
2. Оба прямоугольника получают это новое значение координаты Y. На этом этапе rect1 и rect2 имеют идентичные дробные координаты (например, 5.15, 10.30 и т.д.).
3. Для прямоугольника rect2 вызывается статический метод Phaser.Geom.Rectangle.Floor(). Этот метод принимает объект прямоугольника в качестве аргумента и модифицирует его, округляя его свойства `x,y,widthиheight` до ближайших целых чисел в меньшую сторону (Math.floor).
Визуализация и результат
После расчёта позиций необходимо очистить холст и перерисовать прямоугольники, чтобы увидеть изменения.
this.graphics.clear();
this.graphics.fillRectShape(this.rect1);
this.graphics.fillRectShape(this.rect2);
}
}
Метод this.graphics.clear() стирает всё, что было нарисовано в предыдущем кадре. Затем с помощью fillRectShape() оба прямоугольника отрисовываются заново.
В результате вы увидите, что левый прямоугольник (rect1) движется максимально плавно, но его пиксельные границы могут выглядеть размытыми или "дрожать" из-за субпиксельного рендеринга дробных координат. Правый прямоугольник (rect2) движется дискретно, "прилипая" к целым координатам. Его движение выглядит более резким, но границы всегда остаются чёткими, что исключает визуальные артефакты.
Конфигурация и запуск игры
Стандартный блок конфигурации Phaser Game создаёт экземпляр игры с нашей сценой.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Этот код создаёт игровое окно размером 800x600 пикселей с автоматическим выбором рендерера (WebGL или Canvas) и указывает наш класс Example в качестве основной сцены.
Что попробовать дальше
Метод Phaser.Geom.Rectangle.Floor — это простой, но мощный инструмент для контроля над отображением геометрических объектов. Он незаменим для задач, требующих жёсткого позиционирования по целым пикселям: создание тайловых карт, пиксель-арт анимаций или интерфейсов.
**Идеи для экспериментов:**
1. Попробуйте применить метод Floor не только к rect2.y, но и к rect2.x, двигая прямоугольник по диагонали.
2. Сравните результат с методом Phaser.Geom.Rectangle.Ceil (округление в большую сторону) или просто с округлением Math.round.
3. Создайте спрайт и привяжите его положение к координатам округлённого прямоугольника, чтобы увидеть, как это влияет на движение игровых персонажей.
