О чем этот пример
При работе с тайловыми картами в Phaser иногда требуется динамически изменять видимую область слоя, не затрагивая исходные данные карты. В этом примере показано, как свойство `layer.width` позволяет обрезать или "маскировать" слой, создавая интересные визуальные эффекты или ограничивая область отрисовки для оптимизации. Этот приём полезен для создания динамических уровней, скрытия частей карты до определённого момента или просто для экспериментов с геймплеем.
Версия 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');
this.load.tilemapTiledJSON('map3', 'assets/tilemaps/maps/super-mario-3.json');
this.load.image('tiles3', 'assets/tilemaps/tiles/super-mario-3.png');
}
create ()
{
const map1 = this.make.tilemap({ key: 'map1' });
const tileset1 = map1.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layer1 = map1.createLayer('World1', tileset1, 0, 0);
layer1.width = 200;
const map2 = this.add.tilemap('map3');
const tileset2 = map2.addTilesetImage('SuperMarioBrosMap1-3_bank.png', 'tiles3');
const layer2 = map2.createLayer('ShoeBox Tile Grab', tileset2, 900, 300);
const cursors = this.input.keyboard.createCursorKeys();
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
speed: 0.5
};
this.controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig);
this.cameras.main.setBounds(0, 0, layer2.x + layer2.width, 0);
}
update (time, delta)
{
this.controls.update(delta);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ресурсов
В методе preload() загружаются два набора ресурсов для тайловых карт. Каждый набор состоит из JSON-файла карты (Tilemap Tiled JSON) и изображения с тайлами. Обратите внимание на использование this.load.setBaseURL() для указания базового URL, что позволяет использовать относительные пути для ресурсов.
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');
this.load.tilemapTiledJSON('map3', 'assets/tilemaps/maps/super-mario-3.json');
this.load.image('tiles3', 'assets/tilemaps/tiles/super-mario-3.png');
Создание карт и слоёв
В методе create() создаются две независимые тайловые карты и их визуальные слои. Обратите внимание на два разных способа создания карты: через this.make.tilemap() и this.add.tilemap(). Оба метода допустимы и возвращают экземпляр Tilemap. Для каждой карты добавляется tileset (набор тайлов) и создаётся слой (Layer). Слои позиционируются на экране с помощью параметров `xиy`.
const map1 = this.make.tilemap({ key: 'map1' });
const tileset1 = map1.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layer1 = map1.createLayer('World1', tileset1, 0, 0);
const map2 = this.add.tilemap('map3');
const tileset2 = map2.addTilesetImage('SuperMarioBrosMap1-3_bank.png', 'tiles3');
const layer2 = map2.createLayer('ShoeBox Tile Grab', tileset2, 900, 300);
Ключевой момент: управление шириной слоя
Сразу после создания первого слоя (layer1) его свойству width присваивается значение 200. Это действие не изменяет саму карту данных, а влияет на отрисовку. Слой будет отображать только первые 200 тайлов по горизонтали от своей начальной точки, создавая эффект обрезки. Это мощный инструмент для управления визуальным представлением без модификации исходных данных.
layer1.width = 200;
Настройка камеры и управления
Для навигации по сцене настраивается управление камерой с клавиатуры. Создаётся объект Phaser.Cameras.Controls.FixedKeyControl, который привязывает стрелки влево/вправо к перемещению камеры. Границы камеры (bounds) устанавливаются так, чтобы правая граница равнялась сумме позиции второго слоя (layer2.x) и его полной ширины (layer2.width). Это позволяет камере прокручивать всю область второго слоя.
const cursors = this.input.keyboard.createCursorKeys();
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
speed: 0.5
};
this.controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig);
this.cameras.main.setBounds(0, 0, layer2.x + layer2.width, 0);
Обновление состояния
В методе update() вызывается this.controls.update(delta). Это обеспечивает плавное перемещение камеры в зависимости от нажатых клавиш и времени, прошедшего с предыдущего кадра (delta). Без этого вызова управление камерой не будет работать.
update (time, delta)
{
this.controls.update(delta);
}
Конфигурация игры
Конфигурационный объект задаёт основные параметры игры: тип рендерера, размеры холста, цвет фона, контейнер для встраивания в HTML и важный флаг pixelArt: true. Этот флаг отключает сглаживание текстур при масштабировании, что критично для сохранения чёткого пиксельного стиля старых игр. Также здесь указывается основной класс сцены.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Изменение свойства width (или height) слоя Tilemap — это простой, но эффективный способ управлять видимой областью карты в реальном времени. Вы можете использовать это для создания анимаций открытия дверей, постепенного раскрытия уровня, оптимизации (скрывая далёкие части) или создания нестандартных игровых механик. Попробуйте экспериментировать: изменяйте размер слоя в update() в зависимости от действий игрока, создавайте плавные переходы с помощью твинов или комбинируйте несколько обрезанных слоёв для сложных эффектов.
