О чем этот пример
Разработка мобильных игр часто сопровождается проблемами отображения на разных устройствах. Один из коварных багов — это неожиданное поведение автоцентровки (`autoCenter`) в iOS, когда игровая сцена может смещаться или масштабироваться не так, как задумано. Эта статья поможет вам понять, как отлаживать подобные проблемы, используя визуальные дебаг-инструменты прямо в Phaser. Вы научитесь быстро выявлять и исправлять несоответствия в позиционировании, что особенно критично для пиксель-арт игр, где каждый пиксель на счету.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var gameContainerSizeDebug;
class MainScene extends Phaser.Scene {
constructor() {
super({ key: "MainScene" });
}
create() {
gameContainerSizeDebug = this.add.graphics({
lineStyle: { width: 1, color: 0xffffff, alpha: 1 },
fillStyle: { color: 0xff0000, alpha: 0 }
}).strokeRect(0, 0, 144, 256).strokeCircle(144 / 2, 256 / 2, 42).beginPath().moveTo(0, 0).lineTo(144, 256).strokePath().beginPath().moveTo(144, 0).lineTo(0, 256).strokePath().beginPath().moveTo(-1024, 256/2).lineTo(1024,256/2).strokePath().beginPath().moveTo(144/2, -1024).lineTo(144/2,1024).strokePath();
}
}
const config = {
type: Phaser.AUTO,
width: 144,
height: 256,
backgroundColor: '#333',
pixelArt: true,
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
zoom: 1,
},
scene: [ MainScene ]
};
const game = new Phaser.Game(config)
// http://bs-local.com:8080/mobile.html?src=src\bugs\6862%20iOS%20autocenter%20inconsistent.js
// https://phaser.io/sandbox/A3KSEgq7
Проблема: автоцентровка работает неодинаково
При использовании Phaser.Scale.FIT и Phaser.Scale.CENTER_BOTH движок должен автоматически центрировать и подгонять размер игрового холста под доступное пространство на устройстве. Однако на iOS могут возникать расхождения: например, сцена центрируется не по пиксельной сетке, что приводит к размытости в пиксель-арте, или смещается относительно физических границ экрана.
Этот баг сложно уловить "на глаз", особенно если интерфейс игры не имеет четких ориентиров. Нужен надежный способ визуализации реальных границ и центра игрового мира.
Создаем дебаг-слой для визуализации
В примере используется объект Graphics для отрисовки примитивов прямо поверх игрового мира. Это позволяет в реальном времени увидеть, где находятся ключевые точки.
Создаем графический объект в методе create() сцены. Мы задаем ему стиль линии и заливки. Обратите внимание, что заливка полностью прозрачна (alpha: 0), так как нам нужны только контуры.
gameContainerSizeDebug = this.add.graphics({
lineStyle: { width: 1, color: 0xffffff, alpha: 1 },
fillStyle: { color: 0xff0000, alpha: 0 }
});
Рисуем ориентиры: прямоугольник, круг и оси
После создания объекта мы вызываем цепочку методов для отрисовки фигур. Каждая фигура служит определенной цели для отладки.
1. **Прямоугольник (strokeRect)**: Обозначает номинальные границы игрового мира (144x256 пикселей). Если он не совпадает с видимой областью на устройстве — проблема в масштабировании.
2. **Круг (strokeCircle)**: Показывает центр игрового мира. Его смещение от визуального центра экрана устройства укажет на проблему с autoCenter.
3. **Диагонали и оси**: Длинные линии, выходящие за границы прямоугольника, помогают оценить смещение и понять, где находится "ноль" координат (верхний левый угол мира).
.strokeRect(0, 0, 144, 256)
.strokeCircle(144 / 2, 256 / 2, 42)
.beginPath().moveTo(0, 0).lineTo(144, 256).strokePath()
.beginPath().moveTo(144, 0).lineTo(0, 256).strokePath()
.beginPath().moveTo(-1024, 256/2).lineTo(1024,256/2).strokePath()
.beginPath().moveTo(144/2, -1024).lineTo(144/2,1024).strokePath();
Настройка Scale Manager — ключ к пониманию
Поведение центрирования и масштабирования полностью определяется конфигурацией scale в объекте конфига игры.
* mode: Phaser.Scale.FIT гарантирует, что игра впишется в доступную область, сохраняя пропорции. Могут появиться черные поля (letterbox).
* autoCenter: Phaser.Scale.CENTER_BOTH центрирует игровую область по горизонтали и вертикали внутри этих полей.
* zoom: 1 устанавливает базовый уровень масштаба. Изменение этого значения может использоваться для принудительного пиксельного соответствия на HiDPI-экранах.
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
zoom: 1,
}
Как интерпретировать результат на устройстве
Запустите игру на целевом iOS-устройстве или в симуляторе.
* **Идеальный случай**: Белый прямоугольник и круг находятся ровно по центру экрана устройства, линии осей делят экран пополам. Черные поля (если есть) симметричны.
* **Признак проблемы**: Прямоугольник смещен в сторону, круг не в центре экрана, оси проходят не через визуальный центр. Это прямое указание на баг в реализации autoCenter для данной версии iOS/браузера.
Полученную "картинку" можно сфотографировать или сделать скриншот — это будет наглядное доказательство проблемы для issue-трекера или для поиска workaround.
Что попробовать дальше
Использование графического дебаг-слоя — это простой и мощный способ диагностики проблем с отображением на разных платформах. С его помощью вы можете не только подтвердить баг, но и начать искать обходные пути: например, вручную корректировать позицию сцены после определения реальных границ через this.scale.gameSize или this.cameras.main. Для экспериментов попробуйте изменить mode на Phaser.Scale.NONE и самостоятельно реализовать логику позиционирования, или используйте zoom для принудительного целочисленного масштабирования, чтобы избежать размытия пиксель-арта.
