О чем этот пример

При разработке игр часто требуется точное позиционирование объектов, особенно когда речь идет о физике или тайловых картах. Работа с дробными координатами может привести к визуальным артефактам и неожиданному поведению. В этой статье мы разберем, как использовать метод `ceil()` вектора Phaser для округления координат по оси Y в большую сторону, что полезно для выравнивания объектов по сетке или привязки к определенным точкам. Мы рассмотрим практический пример, где наглядно видна разница между исходной дробной координатой и округленной. Этот подход поможет сделать движение объектов более предсказуемым и оптимизировать отрисовку.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    y = 100;
    graphics;
    text2;
    text1;
    point2;
    point1;

    create ()
    {
        this.graphics = this.add.graphics({ fillStyle: { color: 0x2266aa } });

        this.point1 = new Phaser.Math.Vector2(300, 100);
        this.point2 = new Phaser.Math.Vector2(500, 100);

        this.text1 = this.add.text(100, 50, '');
        this.text2 = this.add.text(500, 50, '');
    }

    update ()
    {
        this.y += 0.05;

        this.point1.y = this.point2.y = this.y;
        this.point2.ceil();

        this.text1.setText(`y: ${this.point1.y}`);
        this.text2.setText(`y: ${this.point2.y}`);

        this.graphics.clear();
        this.graphics.fillPointShape(this.point1, 20);
        this.graphics.fillPointShape(this.point2, 20);
    }
}

const config = {
    width: 800,
    height: 600,
    type: Phaser.AUTO,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка сцены и создание точек

В начале кода определяется класс сцены Example. В нем объявляются переменные для хранения координаты Y, графики, текстовых полей и двух векторных точек.

В методе create() инициализируются основные объекты: графический контекст для отрисовки точек, два вектора с одинаковыми начальными координатами по X (300 и 500) и Y (100), а также два текстовых поля для вывода значений.

this.graphics = this.add.graphics({ fillStyle: { color: 0x2266aa } });

this.point1 = new Phaser.Math.Vector2(300, 100);
this.point2 = new Phaser.Math.Vector2(500, 100);

this.text1 = this.add.text(100, 50, '');
this.text2 = this.add.text(500, 50, '');

Анимация и применение метода ceil()

В методе update(), который вызывается каждый кадр, происходит изменение координаты Y. Она плавно увеличивается, создавая эффект движения точек вниз.

Ключевой момент: обе точки получают одинаковое новое значение Y. Однако для второй точки point2 сразу же вызывается метод ceil(). Этот метод округляет координаты вектора (как X, так и Y) до ближайшего большего целого числа. В данном случае меняется только Y, так как X остается статичным.

this.y += 0.05;

this.point1.y = this.point2.y = this.y;
this.point2.ceil();

Визуализация и отображение данных

Чтобы увидеть разницу между исходной и округленной координатами, их значения выводятся в текстовые поля. Метод setText обновляет содержимое text1 и text2.

Затем графический слой очищается методом clear(), и обе точки отрисовываются заново с помощью fillPointShape(). Размер точки задается радиусом в 20 пикселей. Визуально вы увидите, как левая точка движется плавно, а правая — дискретно, «прыгая» на целые значения Y.

this.text1.setText(`y: ${this.point1.y}`);
this.text2.setText(`y: ${this.point2.y}`);

this.graphics.clear();
this.graphics.fillPointShape(this.point1, 20);
this.graphics.fillPointShape(this.point2, 20);

Конфигурация и запуск игры

Код завершается стандартной для Phaser конфигурацией игры. В объекте config задаются размеры холста, тип рендерера (Phaser.AUTO), ID родительского элемента и основная сцена.

Создание экземпляра Phaser.Game с этой конфигурацией запускает выполнение кода.

const config = {
    width: 800,
    height: 600,
    type: Phaser.AUTO,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Что попробовать дальше

Метод ceil() объекта Phaser.Math.Vector2 — простой, но мощный инструмент для контроля над позиционированием. Он незаменим при создании игр с сеточной логикой, например, пошаговых стратегий или головоломок, где объекты должны «прилипать» к узлам сетки. Поэкспериментируйте: попробуйте применить floor() для округления в меньшую сторону или round() для математического округления. Также можно модифицировать код, чтобы округлялись обе координаты (X и Y), и понаблюдать за движением точки по диагонали.