О чем этот пример
При создании 2D-игр в стиле pixel art разработчики часто сталкиваются с визуальными артефактами — 'протеканием' (bleeding) текстур тайлов при скроллинге камеры. Эта проблема портит целостность картины, делая линии размытыми и неровными. В статье разберем готовый тестовый пример из Phaser, который наглядно демонстрирует эту проблему и показывает её изящное решение через правильную настройку рендеринга. Вы узнаете, какие ключевые настройки конфигурации и методы API необходимы для чистого отображения тайловых карт.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('tiles', 'assets/tilemaps/tiles/catastrophi_tiles_16.png');
this.load.tilemapCSV('map', 'assets/tilemaps/csv/catastrophi_level2.csv');
}
create ()
{
const map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
const tileset = map.addTilesetImage('tiles');
const layer = map.createLayer(0, tileset, 0, 0);
// Visual test to make sure tiles don't bleed while scrolling at certain speeds
}
update (time, delta)
{
this.cameras.main.scrollX = (200 + Math.cos(time / 1000) * 200);
this.cameras.main.scrollY = (500 + Math.sin(time / 1000) * 500);
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Суть проблемы: почему текстуры 'протекают'
Артефакт 'протекания' возникает, когда графический процессор при отрисовке текселя (пикселя текстуры) на границе тайла для антиалиасинга берёт данные из соседнего тайла. Это особенно заметно в pixel art, где каждый пиксель важен, и при скроллинге камеры с дробными (нецелыми) координатами появляются цветные полосы между тайлами.
Пример в статье специально создан для визуальной проверки (Visual test), чтобы убедиться, что тайлы не 'протекают' при скроллинге с определёнными скоростями. Камера движется по сложной траектории, что увеличивает вероятность появления артефактов.
Анализ кода: загрузка и создание тайловой карты
Всё начинается с метода preload. Здесь загружаются необходимые ресурсы: тайлсет (изображение с тайлами) и сама карта уровня в формате CSV.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('tiles', 'assets/tilemaps/tiles/catastrophi_tiles_16.png');
this.load.tilemapCSV('map', 'assets/tilemaps/csv/catastrophi_level2.csv');
В методе create происходит основная работа по созданию тайловой карты. Ключевые шаги:
1. Создание объекта Tilemap из загруженных CSV-данных с указанием размера тайла.
2. Связывание тайлсета (изображения) с картой.
3. Создание слоя для отрисовки.
const map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
const tileset = map.addTilesetImage('tiles');
const layer = map.createLayer(0, tileset, 0, 0);
Движение камеры и симуляция проблемы
Чтобы проверить отображение тайлов в динамике, в методе update реализовано плавное движение камеры по синусоидальной траектории. Это приводит к постоянному изменению её координат scrollX и scrollY, часто на дробные значения.
this.cameras.main.scrollX = (200 + Math.cos(time / 1000) * 200);
this.cameras.main.scrollY = (500 + Math.sin(time / 1000) * 500);
Именно такое движение с дробными координатами и является триггером для появления артефактов 'протекания', если рендеринг настроен неправильно.
Ключевое решение: настройка `pixelArt` в конфиге
Самый важный момент, который предотвращает проблему в данном примере, — это настройка pixelArt: true в объекте конфигурации игры (config).
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: true, // Критически важная настройка для pixel art
scene: Example
};
Что делает эта настройка на низком уровне:
1. **Отключает линейную фильтрацию текстур** (LINEAR) и включает точечную (NEAREST). Это гарантирует, что при масштабировании или смещении пиксели остаются чёткими, без размытия.
2. **Автоматически округляет координаты отрисовки** (roundPixels: true) на уровне камеры. Это предотвращает смещение на долю пикселя, которое и вызывает 'протекание'. Без этого даже с точечной фильтрацией могут появляться артефакты при скроллинге.
Использование this.make.tilemap вместо this.add.tilemap также может играть роль, так как фабричный метод make лучше интегрируется с внутренними системами управления текстурами для pixel art.
Что попробовать дальше
Для чистого отображения pixel art тайловых карт в Phaser при динамическом скроллинге достаточно одной ключевой настройки в конфигурации игры — pixelArt: true. Она комплексно решает проблемы фильтрации и округления координат. Для экспериментов попробуйте установить pixelArt: false в примере и увидите появление артефактов. Также можно поэкспериментировать с ручным управлением свойствами roundPixels у камеры или antialias в настройках рендерера, чтобы глубже понять их взаимодействие.
