О чем этот пример
При разработке игр с большими уровнями (платформеры, RPG, стратегии) производительность рендеринга тайловых карт становится критичной. Phaser предлагает два принципиально разных подхода: классический CPU-рендеринг и аппаратно-ускоренный GPU-рендеринг. В этой статье мы разберем, как работают оба метода на примере уровня из Super Mario, научимся переключаться между ними в реальном времени и поймем, когда какой подход выгоднее использовать для вашего проекта.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
controls;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.tilemapTiledJSON('map1', 'assets/tilemaps/maps/super-mario.json');
this.load.image('tiles1', 'assets/tilemaps/tiles/super-mario.png');
}
create ()
{
const mapCPU = this.make.tilemap({ key: 'map1' });
const tilesetCPU = mapCPU.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layerCPU = mapCPU.createLayer('World1', tilesetCPU, 0, 0).setScale(2.5);
const mapGPU = this.make.tilemap({ key: 'map1' });
const tilesetGPU = mapGPU.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layerGPU = mapGPU.createLayer('World1', tilesetGPU, 0, 0, true).setScale(2.5).setVisible(false);
this.mode = 'CPU';
this.text = this.add.text(16, 16, `Click to switch to ${this.mode === 'CPU' ? 'GPU' : 'CPU'} mode.\nThis tilemap is using the ${this.mode} for rendering.`);
const cursors = this.input.keyboard.createCursorKeys();
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
up: cursors.up,
down: cursors.down,
speed: 0.5
};
this.controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig);
this.cameras.main.setBounds(0, 0, layerCPU.x + layerCPU.width, layerCPU.height * 3);
this.input.on('pointerdown', () => {
if (this.mode === 'CPU')
{
layerCPU.setVisible(false);
layerGPU.setVisible(true);
this.mode = 'GPU';
}
else
{
layerCPU.setVisible(true);
layerGPU.setVisible(false);
this.mode = 'CPU';
}
this.text.setText(`Click to switch to ${this.mode === 'CPU' ? 'GPU' : 'CPU'} mode.\nThis tilemap is using the ${this.mode} for rendering.`);
});
}
update (time, delta)
{
this.controls.update(delta);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: false,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов и подготовка сцены
Основа работы с тайловыми картами в Phaser — это загрузка данных карты (в формате Tiled JSON) и графики тайлов. В методе preload() мы загружаем два ключевых ресурса.
this.load.tilemapTiledJSON('map1', 'assets/tilemaps/maps/super-mario.json');
this.load.image('tiles1', 'assets/tilemaps/tiles/super-mario.png');
После загрузки в методе create() создаются две независимые копии одной и той же карты. Обратите внимание на ключевой пятый параметр в методе createLayer().
const mapCPU = this.make.tilemap({ key: 'map1' });
const tilesetCPU = mapCPU.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layerCPU = mapCPU.createLayer('World1', tilesetCPU, 0, 0).setScale(2.5);
const mapGPU = this.make.tilemap({ key: 'map1' });
const tilesetGPU = mapGPU.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layerGPU = mapGPU.createLayer('World1', tilesetGPU, 0, 0, true).setScale(2.5).setVisible(false);
Параметр true в createLayer('World1', tilesetGPU, 0, 0, true) активирует GPU-рендеринг для этого слоя. По умолчанию (как в слое layerCPU) этот параметр равен false, что означает использование CPU.
Суть различий: CPU и GPU рендеринг
**CPU-рендеринг (Canvas):** Phaser отрисовывает каждый видимый тайл на холсте (Canvas) используя JavaScript и Canvas API. Это классический, хорошо поддерживаемый способ. Каждый кадр система перебирает видимые тайлы и рисует их как отдельные изображения. Это может создавать нагрузку на процессор при очень больших или сложных картах.
**GPU-рендеринг (WebGL):** Данные тайловой карты (позиции, индексы тайлов) передаются в видеопамять (VRAM) видеокарты. Рендерингом полностью управляет графический процессор через шейдеры. Это снимает нагрузку с CPU и значительно ускоряет отрисовку, особенно когда на экране много статичных тайлов. Однако этот режим требует поддержки WebGL и может иметь особенности с отрисовкой пиксель-арта.
В примере мы создали оба слоя сразу, но изначально виден только CPU-слой. GPU-слой скрыт методом .setVisible(false).
Управление камерой и переключение режимов
Для навигации по большой карте в примере используется система управления камерой Phaser.Cameras.Controls.FixedKeyControl. Она привязывает стрелки клавиатуры к перемещению камеры.
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
up: cursors.up,
down: cursors.down,
speed: 0.5
};
this.controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig);
Камере устанавливаются границы, соответствующие размеру карты, чтобы она не выходила за ее пределы.
this.cameras.main.setBounds(0, 0, layerCPU.x + layerCPU.width, layerCPU.height * 3);
Самое интересное — обработчик клика мыши, который переключает видимость слоев, меняя активный режим рендеринга.
this.input.on('pointerdown', () => {
if (this.mode === 'CPU') {
layerCPU.setVisible(false);
layerGPU.setVisible(true);
this.mode = 'GPU';
} else {
layerCPU.setVisible(true);
layerGPU.setVisible(false);
this.mode = 'CPU';
}
this.text.setText(`Click to switch to ${this.mode === 'CPU' ? 'GPU' : 'CPU'} mode.\nThis tilemap is using the ${this.mode} for rendering.`);
});
Таким образом, переключение происходит мгновенно, так как оба слоя уже созданы и находятся на своих местах.
Когда использовать CPU, а когда GPU?
Выбор режима зависит от специфики вашей игры и целевой платформы.
**Выбирайте CPU-рендеринг, если:** * Вы создаете пиксель-арт игру и хотите гарантированно четкое отображение без смазывания (фильтрация текстур в WebGL может мешать). * Целевая аудитория может использовать старые устройства или браузеры без хорошей поддержки WebGL. * Ваша тайловая карта небольшая, и разница в производительности будет незаметна.
**Выбирайте GPU-рендеринг, если:** * У вас огромные, плотные тайловые карты (открытый мир, большие подземелья). * Критична производительность и плавность FPS, особенно на мобильных устройствах. * Вы используете эффекты камеры (размытие, свечение), которые сами требуют WebGL.
В конфиге игры важно свойство pixelArt: false. Для пиксель-арта в GPU-режиме его следует установить в true, чтобы отключить линейную фильтрацию текстур и сохранить четкость.
Что попробовать дальше
Phaser дает разработчику гибкий контроль над рендерингом тайловых карт. Используйте CPU-режим для максимальной совместимости и пиксель-арта, GPU-режим — для сложных уровней, где важна производительность. Для экспериментов попробуйте
- создать карту с тысячами тайлов и сравнить FPS в обоих режимах
- включить
pixelArt: trueв конфиге и увидеть разницу в отрисовке - добавить на сцену множество анимированных спрайтов и проверить, как меняется нагрузка при разных типах рендеринга фона
