О чем этот пример
При разработке игр часто требуется работать с координатами объектов, особенно когда речь идет о плавной анимации и физике. Однако не всегда нам нужны дробные значения — иногда позиция должна быть «привязана» к целым числам, например, для пиксель-арт стилистики или сеточного движения. В этой статье мы разберем, как метод `floor()` класса `Phaser.Math.Vector2` позволяет легко и эффективно округлять координаты вектора до целых чисел вниз, и как это можно использовать на практике. Мы рассмотрим конкретный пример, где две точки движутся синхронно по вертикали, но одна из них демонстрирует «сырые» координаты с плавающей запятой, а вторая — округленные. Это наглядная демонстрация того, как просто можно управлять точностью позиционирования объектов в вашей игре.
Версия 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.floor();
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. В нем объявляются несколько свойств: две текстовые метки (text1, text2), два вектора (point1, point2), объект для рисования (graphics) и переменная `y` для управления вертикальным движением.
В методе create() инициализируются основные объекты:
this.graphics = this.add.graphics({ fillStyle: { color: 0x2266aa } });
Здесь создается объект Graphics с синим цветом заливки, который будет использоваться для отрисовки точек.
Далее создаются два экземпляра вектора Phaser.Math.Vector2. Они представляют собой точки в 2D-пространстве с начальными координатами (300, 100) и (500, 100).
this.point1 = new Phaser.Math.Vector2(300, 100);
this.point2 = new Phaser.Math.Vector2(500, 100);
Также создаются две текстовые метки для отображения текущих координат Y каждой точки. Их начальный текст пустой, он будет обновляться в update().
Анимация и применение метода floor()
Основная логика анимации находится в методе update(), который вызывается каждый кадр.
Сначала увеличивается значение переменной `y` на небольшую величину (0.05). Это создает плавное вертикальное движение.
this.y += 0.05;
Затем это новое значение `yприсваивается свойству.y` обоих векторов. Таким образом, обе точки движутся синхронно вниз с одинаковой скоростью.
this.point1.y = this.point2.y = this.y;
Ключевой момент: к вектору point2 применяется метод floor().
this.point2.floor();
Метод floor() класса Phaser.Math.Vector2 округляет **каждую** компоненту вектора (X и Y) до ближайшего меньшего целого числа (математическая функция «пол»). В нашем примере координата X у point2 равна 500 (целое число), а координата Y — это значение this.y, которое с каждым кадром становится дробным (например, 100.05, 100.10 и т.д.). Метод floor() берет это дробное значение Y и превращает его, например, в 100, пока this.y не достигнет 101.
Визуализация и отображение данных
После обновления координат необходимо обновить текстовые метки, чтобы отобразить текущие значения Y для каждой точки. Для point1 мы показываем исходное дробное значение, для point2 — уже округленное методом floor().
this.text1.setText(`y: ${this.point1.y}`);
this.text2.setText(`y: ${this.point2.y}`);
Перед отрисовкой точек важно очистить холст Graphics от предыдущего кадра, иначе мы увидим следы от старых позиций.
this.graphics.clear();
Наконец, рисуются сами точки в виде залитых кругов с радиусом 20 пикселей в текущих координатах каждого вектора.
this.graphics.fillPointShape(this.point1, 20);
this.graphics.fillPointShape(this.point2, 20);
Метод fillPointShape() принимает объект, реализующий интерфейс точки (как Vector2), и радиус.
Конфигурация и запуск игры
Для запуска примера необходимо создать конфигурационный объект игры и инициализировать экземпляр Phaser.Game.
Конфигурация задает размеры окна (800x600), автоматический выбор рендерера (Phaser.AUTO), идентификатор HTML-контейнера и ссылку на наш класс сцены Example.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
После этого Phaser берет на себя управление циклом обновления и отрисовки, вызывая методы create() один раз при инициализации, а update() — на каждом кадре.
Что попробовать дальше
Метод floor() для векторов в Phaser — это простой, но мощный инструмент для контроля над координатами. Он незаменим, когда вам нужно «привязать» движение спрайта к сетке, обеспечить четкое пиксельное позиционирование или согласовать координаты с тайловой картой, где индексы ячеек являются целыми числами.
**Идеи для экспериментов:**
1. Попробуйте применить floor() не только к Y, но и к X-координате, управляя движением по горизонтали.
2. Создайте спрайт и привяжите его позицию к округленному вектору, чтобы увидеть «ступенчатое» движение.
3. Используйте метод round() (округляет до ближайшего целого) или ceil() (округляет вверх) класса Vector2 и сравните визуальный результат с floor().
4. Поэкспериментируйте с анимацией по диагонали, применяя округление к обоим компонентам вектора.
