О чем этот пример
Управление объектами с клавиатуры — фундаментальный навык в разработке игр. В этой статье мы подробно разберем официальный пример Phaser 3, который демонстрирует управление физическим спрайтом с помощью стрелок. Вы научитесь инициализировать слушатели клавиш, привязывать их к движению объекта и правильно структурировать код в методах жизненного цикла сцены. Этот паттерн является основой для создания платформеров, головоломок и аркадных игр.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
player;
cursors;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
this.cursors = this.input.keyboard.createCursorKeys();
this.player = this.physics.add.image(400, 300, 'block');
this.player.setCollideWorldBounds(true);
}
update ()
{
this.player.setVelocity(0);
if (this.cursors.left.isDown)
{
this.player.setVelocityX(-300);
}
else if (this.cursors.right.isDown)
{
this.player.setVelocityX(300);
}
if (this.cursors.up.isDown)
{
this.player.setVelocityY(-300);
}
else if (this.cursors.down.isDown)
{
this.player.setVelocityY(300);
}
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
backgroundColor: '#0072bc',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
scene: Example
};
const game = new Phaser.Game(config);
Инициализация управления и создание спрайта
Вся логика примера содержится внутри класса сцены Example. Управление создается и настраивается в методе create(), который выполняется один раз при старте сцены.
Сначала мы получаем доступ к курсорным клавишам (стрелкам) через менеджер ввода Phaser. Это стандартный способ для быстрого доступа к основным клавишам направления.
this.cursors = this.input.keyboard.createCursorKeys();
Затем создается физический спрайт — игровой объект, с которым связан Arcade Physics. Мы помещаем его в центр экрана (координаты 400x300) и указываем ключ загруженного изображения.
this.player = this.physics.add.image(400, 300, 'block');
this.player.setCollideWorldBounds(true);
Метод setCollideWorldBounds(true) — это важный вызов физического движка. Он гарантирует, что спрайт не сможет вылететь за границы игрового мира, что критически важно для большинства игр.
Логика движения в методе update
Основная логика перемещения находится в методе update(), который вызывается на каждом кадре игры. Это идеальное место для обработки ввода и изменения состояния объектов.
Первым делом мы сбрасываем скорость спрайта до нуля по обеим осям. Это необходимо, чтобы движение прекращалось, когда игрок отпускает клавиши. Без этого сброса спрайт продолжал бы двигаться с последней заданной скоростью.
this.player.setVelocity(0);
Далее мы проверяем состояние каждой курсорной клавиши. Объект this.cursors содержит свойства left, right, up, down, каждое из которых является объектом Key. Его метод isDown возвращает true, если клавиша нажата в данный момент.
if (this.cursors.left.isDown)
{
this.player.setVelocityX(-300);
}
else if (this.cursors.right.isDown)
{
this.player.setVelocityX(300);
}
Аналогичная логика применяется для вертикального движения. Обратите внимание, что используется метод setVelocityX и setVelocityY. Это методы Arcade Physics, которые напрямую задают линейную скорость тела, создавая мгновенное, "коробочное" движение, характерное для многих аркадных игр.
Настройка физики и запуск игры
Конфигурация игры определяет ее базовые параметры. Ключевой раздел здесь — physics, который активирует Arcade Physics и включает режим отладки.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
backgroundColor: '#0072bc',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
scene: Example
};
Параметр debug: true включает отладочную визуализацию для всех физических тел. На экране вокруг спрайта block вы увидите зеленый контур — это границы физического тела (хитбокс), которое рассчитывает столкновения. Это невидимая область, которая может отличаться от графического спрайта.
После создания конфигурации происходит инстанцирование игры, которое запускает весь жизненный цикл.
const game = new Phaser.Game(config);
Почему именно такая структура кода?
Пример демонстрирует каноничную, чистую архитектуру Phaser 3, разделяя код по методам жизненного цикла сцены.
* **preload()**: Здесь загружаются ассеты (изображения, звуки). Это гарантирует, что к моменту создания объектов они уже будут в памяти.
* **create()**: Здесь происходит однократная инициализация объектов сцены, создание физических тел, настройка управления и игровой логики. Вызов createCursorKeys() помещают сюда, так как создавать слушатели ввода многократно в update() — ошибка.
* **update()**: Сюда помещается код, который должен выполняться непрерывно — проверка ввода, пересчет скоростей, проверка условий победы. Именно поэтому проверка isDown и вызов setVelocity находятся здесь.
Такое разделение делает код предсказуемым, удобным для отладки и масштабирования. Например, вы можете легко добавить в create() создание врагов или препятствий, а логику их взаимодействия с игроком перенести в update().
Что попробовать дальше
Вы разобрали базовый, но мощный паттерн управления в Phaser 3. Он использует встроенный менеджер ввода для клавиатуры и физический движок Arcade для перемещения объектов. Для экспериментов попробуйте: изменить значение скорости (300) на большее или меньшее; добавить ускорение вместо мгновенной скорости; привязать управление к клавишам WASD, используя this.input.keyboard.addKeys(); или добавить второй спрайт, управляемый другим набором клавиш, для создания локального мультиплеера.
