О чем этот пример
Ранние платформеры, такие как Super Mario Bros, определили стандарт скроллинговых уровней. В современных играх на Phaser этот принцип оживает благодаря тайловым картам и умной камере. Эта статья покажет, как загрузить карту из Tiled, масштабировать её и реализовать плавное управление камерой с клавиатуры — основа для многих 2D-игр. Вы научитесь связывать JSON-карту из редактора Tiled со спрайтшитом, создавать игровой слой и настраивать камеру, которая следует за действиями игрока или, как в нашем примере, управляется вручную. Это фундамент для построения больших миров, выходящих за пределы одного экрана.
Версия 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 map1 = this.make.tilemap({ key: 'map1' });
const tileset1 = map1.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layer1 = map1.createLayer('World1', tileset1, 0, 0).setScale(2.5);
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, layer1.x + layer1.width, layer1.height * 3);
}
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);
Подготовка ресурсов: карта и тайлы
Работа начинается с загрузки двух ключевых ресурсов: файла карты в формате JSON, экспортированного из Tiled, и изображения тайлсета (спрайтшита). Phaser позволяет легко разделить данные уровня (расположение тайлов, слои, свойства) и их визуальное представление.
В методе preload мы используем 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');
Создание и отрисовка игрового слоя
В методе create мы создаём объект тайловой карты, связываем его с загруженным изображением тайлов и, наконец, создаём видимый слой. Ключевой момент — использование имени тайлсета, заданного в Tiled ('SuperMarioBros-World1-1'), для правильного сопоставления.
Созданный слой сразу масштабируется методом .setScale(2.5), увеличивая пиксель-арт графику для более ретро-вида. Это демонстрирует гибкость Phaser: вы можете менять масштаб уже после создания уровня.
const map1 = this.make.tilemap({ key: 'map1' });
const tileset1 = map1.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
const layer1 = map1.createLayer('World1', tileset1, 0, 0).setScale(2.5);
Настройка управления камерой с клавиатуры
Чтобы исследовать большую карту, нам нужно управлять камерой. Phaser предоставляет готовый класс Phaser.Cameras.Controls.FixedKeyControl. Сначала создаём объект с конфигурацией, где привязываем стрелки клавиатуры к направлениям движения камеры и задаём скорость её перемещения.
Важно установить границы (bounds) для камеры, чтобы она не уходила за пределы уровня. Границы рассчитываются на основе размеров масштабированного слоя.
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, layer1.x + layer1.width, layer1.height * 3);
Обновление состояния камеры в игровом цикле
Логика управления камерой должна обновляться каждый кадр. Для этого в методе update мы вызываем метод update объекта this.controls, передавая ему дельту времени (delta). Это обеспечивает плавное и независимое от частоты кадров движение.
update (time, delta)
{
this.controls.update(delta);
}
Конфигурация игры: важность флага pixelArt
Корневая конфигурация игры (config) определяет основные параметры. Обратите внимание на свойство pixelArt. В нашем примере оно установлено в false, что означает стандартную линейную фильтрацию текстур при масштабировании. Для сохранения чёткости пиксель-арт графики (как в оригинальном спрайтшите Mario) это значение нужно установить в true. Это предотвратит размытие тайлов при масштабировании.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: false, // Измените на true для чёткого пиксель-арта
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Вы создали базовый движущийся мир: карта загружается, масштабируется и позволяет камере путешествовать по ней с клавиатуры. Это основа для платформера, RPG или исследовательской игры. Для экспериментов попробуйте
- Включить режим
pixelArt: trueв конфиге, чтобы увидеть разницу - Привязать камеру к спрайту игрока вместо ручного управления, используя
this.cameras.main.startFollow(sprite) - Добавить несколько слоёв карты (например, для фона и переднего плана) и настроить их глубину
