О чем этот пример
Вы когда-нибудь сталкивались с ситуацией, когда графический объект в Phaser отображается не в ожидаемом месте, особенно внутри контейнера? Эта проблема часто возникает из-за непонимания системы координат и точек отсчета. В статье разберем баг на примере рисования окружности в контейнере и объясним, как правильно управлять позицией графики, чтобы избежать подобных ошибок в ваших играх. Понимание этих нюансов сэкономит вам часы отладки и сделает код чище.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var config = {
type: Phaser.CANVAS,
parent: 'phaser-example',
scene: {
create: create
}
};
var game = new Phaser.Game(config);
function create () {
var graphics = this.add.graphics();
graphics.lineStyle(4, 0xff00ff);
graphics.strokeCircle(0, 0, 60);
var container = this.add.container(400, 300, [ graphics ]);
}
Разбор исходного кода
Рассмотрим пример, который демонстрирует распространенную ошибку позиционирования графики внутри контейнера.
var config = {
type: Phaser.CANVAS,
parent: 'phaser-example',
scene: {
create: create
}
};
var game = new Phaser.Game(config);
function create () {
var graphics = this.add.graphics();
graphics.lineStyle(4, 0xff00ff);
graphics.strokeCircle(0, 0, 60);
var container = this.add.container(400, 300, [ graphics ]);
}
Код создает сцену (create) с использованием рендерера Canvas. Внутри функции создается объект Graphics (this.add.graphics()), настраивается стиль линии и рисуется окружность с помощью graphics.strokeCircle(0, 0, 60). Затем этот графический объект помещается в контейнер this.add.container(400, 300, [ graphics ]). На первый взгляд, все логично: контейнер позиционируется в точке (400, 300), а внутри него — окружность. Однако результат может вас удивить.
Проблема: Неявная точка отсчета
Ключевая проблема кроется в методе graphics.strokeCircle(0, 0, 60). Здесь (0, 0) — это координаты центра окружности **относительно точки отсчета самого графического объекта**.
По умолчанию точка отсчета (origin) для объекта Graphics в Phaser находится в его локальных координатах (0, 0). Когда вы рисуете окружность с центром в (0, 0), она фактически рисуется прямо в этой точке отсчета.
Контейнер же позиционирует свои дочерние элементы относительно своей собственной точки отсчета (которая тоже по умолчанию (0, 0)). В итоге, координаты окружности (0, 0) привязываются к точке отсчета контейнера, что приводит к неожиданному смещению. Вместо того чтобы окружность была центрирована внутри контейнера, она рисуется так, будто ее центр совпадает с позицией контейнера на сцене, что выглядит как "сдвиг".
Решение: Корректировка позиции или точки отсчета
Чтобы исправить позиционирование, нужно сместить саму графику внутри контейнера. Есть несколько подходов:
1. **Смещение позиции графики:** Установите позицию графического объекта так, чтобы его содержимое было видно правильно внутри контейнера.
function create () {
var graphics = this.add.graphics();
graphics.lineStyle(4, 0xff00ff);
graphics.strokeCircle(0, 0, 60);
var container = this.add.container(400, 300, [ graphics ]);
// Смещаем графику внутри контейнера
graphics.x = 0;
graphics.y = 0;
}
2. **Использование метода setPosition:** Более явный способ задания позиции.
function create () {
var graphics = this.add.graphics();
graphics.lineStyle(4, 0xff00ff);
graphics.strokeCircle(0, 0, 60);
var container = this.add.container(400, 300, [ graphics ]);
// Устанавливаем позицию графики относительно контейнера
graphics.setPosition(0, 0);
}
3. **Рисование с учетом смещения:** Если вы хотите, чтобы окружность была центрирована в контейнере, можно нарисовать ее с центром в (0, 0), но это требует понимания, что точка отсчета графики уже находится в (0, 0).
В данном примере, поскольку окружность уже нарисована с центром в (0, 0), и контейнер расположен в (400, 300), окружность будет отображаться с центром в этой точке сцены, а не внутри контейнера как ожидалось. Корректировка позиции графики внутри контейнера решает проблему.
Лучшие практики работы с графикой и контейнерами
Чтобы избежать подобных ошибок в будущем, следуйте этим рекомендациям:
- **Всегда задавайте явную позицию для графики:** При создании графических объектов внутри контейнеров устанавливайте их `xиy` свойства, чтобы контролировать положение относительно контейнера.
- **Используйте setOrigin для графики:** Если вам нужно изменить точку отсчета графического объекта, используйте graphics.setOrigin(0.5, 0.5) для центрирования, но помните, что это повлияет на все последующие рисования.
- **Проверяйте координаты в отладчике:** Phaser предоставляет инструменты для визуализации границ и точек отсчета, что упрощает отладку.
- **Документируйте систему координат:** В сложных сценах с множеством контейнеров задокументируйте, какие координаты используются (локальные или глобальные), чтобы не запутаться.
Пример с явным позиционированием:
function create () {
var graphics = this.add.graphics();
graphics.lineStyle(4, 0xff00ff);
// Рисуем окружность с центром в (0, 0)
graphics.strokeCircle(0, 0, 60);
// Создаем контейнер и сразу позиционируем графику внутри него
var container = this.add.container(400, 300, [ graphics ]);
graphics.x = 0;
graphics.y = 0;
}
Что попробовать дальше
Позиционирование графики в контейнерах Phaser требует внимания к точкам отсчета и локальным координатам. Основной вывод: всегда явно задавайте позицию графических объектов внутри контейнеров, чтобы избежать неожиданных смещений. Для экспериментов попробуйте:
- Создать анимированную окружность, которая движется внутри контейнера.
- Использовать несколько графических объектов в одном контейнере с разными позициями.
- Поиграть с методом setOrigin для графики и увидеть, как меняется отображение.
Эти практики помогут вам создавать более предсказуемые и управляемые визуальные элементы в играх.
