О чем этот пример
При разработке игр часто возникает необходимость синхронизировать визуальное положение объектов с их логическими координатами. Особенно это актуально для платформеров, пиксель-арт проектов или при работе с тайловыми картами, где точное позиционирование критично. В этом примере мы разберем, как использовать метод `Phaser.Geom.Rectangle.Ceil()` для округления координат прямоугольника в большую сторону, и в каких игровых ситуациях это может быть полезно для избежания визуальных артефактов и обеспечения четкого позиционирования.
Версия 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.Ceil(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);
Что делает Rectangle.Ceil?
Статический метод Phaser.Geom.Rectangle.Ceil() принимает объект прямоугольника в качестве аргумента и модифицирует его координаты `xиy, округляя их до ближайших больших целых чисел (по математической функцииMath.ceil`). Это изменяет сам переданный объект, а не создает новый.
// rect.x = 100.3, rect.y = 50.7
Phaser.Geom.Rectangle.Ceil(rect);
// После вызова: rect.x = 101, rect.y = 51
В примере из исходника мы видим два прямоугольника, rect1 и rect2. Их координата `yплавно увеличивается в каждом кадре, принимая дробные значения. Однако для второго прямоугольникаrect2каждый раз вызывается методCeil()`, что заставляет его "подпрыгивать" до целочисленной координаты, создавая эффект дискретного движения.
Разбор сцены: создание и анимация
В методе create() инициализируются два прямоугольника и объект Graphics для их отрисовки. Обратите внимание, что изначально оба прямоугольника имеют одинаковые размеры и начальную позицию по оси Y.
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() реализована анимация. Координата `yувеличивается на небольшую дробную величину каждый кадр и присваивается обоим прямоугольникам. Затем кrect2применяетсяRectangle.Ceil()`, после чего оба прямоугольника перерисовываются.
update ()
{
this.y += 0.05;
this.rect1.y = this.rect2.y = this.y;
Phaser.Geom.Rectangle.Ceil(this.rect2);
this.graphics.clear();
this.graphics.fillRectShape(this.rect1);
this.graphics.fillRectShape(this.rect2);
}
Практическое применение в играх
Хотя пример демонстрирует просто визуальный эффект, у округления координат есть важные практические применения:
1. **Совмещение с тайловой картой:** При размещении спрайта на сетке тайлов (например, 32x32 пикселя) дробные координаты могут привести к тому, что спрайт будет отрисовываться между тайлами, вызывая размытие. Ceil() (или его аналоги Floor() и Round()) помогает "привязать" объект к узлам сетки.
2. **Физика и коллизии:** В некоторых простых физических системах или системах обнаружения столкновений на основе сетки работа с целыми координатами упрощает логику и делает ее более предсказуемой.
3. **Пиксель-перфект рендеринг:** Для сохранения четкости пиксель-арт графики при перемещении камеры или объектов часто требуется округление координат перед отрисовкой.
// Пример: привязка спрайта игрока к тайловой сетке
function snapToGrid(sprite, tileSize) {
// Создаем временный прямоугольник на основе спрайта
let bounds = new Phaser.Geom.Rectangle(sprite.x, sprite.y, sprite.width, sprite.height);
// Округляем его координаты в большую сторону с учетом размера тайла
bounds.x = Math.ceil(bounds.x / tileSize) * tileSize;
bounds.y = Math.ceil(bounds.y / tileSize) * tileSize;
// Применяем новые координаты к спрайту
sprite.setPosition(bounds.x, bounds.y);
}
Что попробовать дальше
Метод Phaser.Geom.Rectangle.Ceil — это небольшой, но полезный инструмент для контроля над позиционированием геометрических объектов. Он помогает согласовать логику игры с визуальным представлением, особенно при работе с дискретными пространствами, такими как тайловые карты. Для экспериментов попробуйте заменить Ceil на Phaser.Geom.Rectangle.Floor (округление в меньшую сторону) или Phaser.Geom.Rectangle.Round (математическое округление) и понаблюдайте за разницей в движении. Также можно применить эти методы к координате `x` или одновременно к обеим осям, чтобы создать различные виды привязки объектов к игровому миру.
