О чем этот пример
Управление с клавиатуры — фундамент для многих игровых механик, от перемещения персонажа до активации способностей. Phaser предоставляет несколько подходов к обработке ввода: от подписки на глобальные события до прямого опроса состояния клавиш в игровом цикле. Понимание различий между этими методами — ключ к созданию отзывчивого и предсказуемого управления. В этой статье мы разберем пример исходного кода, показывающий все основные способы работы с клавиатурой в движке.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
BKey;
create ()
{
// Global event listener, catches all keys
// Receives every single key down event, regardless of type
this.input.keyboard.on('keydown', event =>
{
console.dir(event);
});
// Hook to a specific key without creating a new Key object (in this case the A key)
this.input.keyboard.on('keydown-A', event =>
{
console.log('Hello from the A Key!');
});
this.input.keyboard.on('keyup-RIGHT', event =>
{
console.log('right up!');
});
// Fire only once on a specific key up event (in this case the S key)
this.input.keyboard.on('keyup-S', function (event)
{
console.log('Keyboard Events Stopped');
this.input.keyboard.stopListeners();
}, this);
// Create a Key object we can poll directly in a tight loop
this.BKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.B);
}
update ()
{
if (this.BKey.isDown)
{
console.log('B!');
}
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
input: {
queue: true
},
scene: Example
};
const game = new Phaser.Game(config);
Глобальный слушатель событий
Самый широкий способ перехвата ввода — подписаться на событие keydown глобально. Этот обработчик будет срабатывать при нажатии *любой* клавиши, что полезно для отладки или создания систем, которым нужна информация о всех действиях игрока.
this.input.keyboard.on('keydown', event => {
console.dir(event);
});
Метод this.input.keyboard.on регистрирует функцию обратного вызова. Переданный объект event содержит детальную информацию о нажатии: код клавиши, модификаторы (Shift, Ctrl) и другие свойства. Однако такой подход неудобен для обработки конкретных действий (например, движения), так как требует постоянной фильтрации событий внутри колбэка.
События для конкретных клавиш
Phaser позволяет создавать именованные события для конкретных клавиш, комбинируя тип события и код клавиши. Это делает код чище и избавляет от необходимости проверять event.keyCode внутри обработчика.
// Сработает только при нажатии 'A'
this.input.keyboard.on('keydown-A', event => {
console.log('Hello from the A Key!');
});
// Сработает только при отпускании стрелки 'RIGHT'
this.input.keyboard.on('keyup-RIGHT', event => {
console.log('right up!');
});
Синтаксис прост: 'keydown-' или 'keyup-' плюс имя клавиши из перечисления Phaser.Input.Keyboard.KeyCodes. Этот метод идеален для обработки разовых действий, например, выстрела или прыжка, которые привязаны к конкретному событию нажатия или отпускания.
Управление слушателями и контекст
Иногда нужно остановить всю обработку клавиатуры. Для этого используется метод stopListeners(). Важно правильно передать контекст (this) в обработчик, чтобы внутри функции можно было обратиться к методам сцены.
this.input.keyboard.on('keyup-S', function (event) {
console.log('Keyboard Events Stopped');
this.input.keyboard.stopListeners(); // 'this' теперь ссылается на сцену
}, this);
Третий аргумент в методе .on() задает контекст выполнения для колбэка. Если его не указать и использовать стрелочную функцию, this внутри функции будет неопределенным, и вызов this.input.keyboard.stopListeners() приведет к ошибке. Это классическая особенность JavaScript, которую важно учитывать в Phaser.
Дискретный опрос состояния (Polling)
Для действий, которые должны повторяться непрерывно, пока зажата клавиша (например, движение), лучше подходит метод дискретного опроса. Вместо событий мы создаем объект Key и проверяем его состояние в методе update(), который вызывается каждый кадр.
create() {
// Создаем объект для клавиши 'B'
this.BKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.B);
}
update() {
// Проверяем состояние каждый кадр
if (this.BKey.isDown) {
console.log('B!');
}
}
Метод addKey создает и возвращает объект типа Phaser.Input.Keyboard.Key. Его свойство isDown будет иметь значение true в течение всех кадров, пока клавиша нажата. Этот подход гарантирует плавное и непрерывное действие, в отличие от событий, которые срабатывают лишь один раз при нажатии.
Конфигурация и очередь событий
Поведение ввода можно тонко настраивать через конфиг игры. В примере активирована опция queue.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
input: {
queue: true // Включает очередь ввода
},
scene: Example
};
Когда queue: true, система ввода начинает сохранять события в очередь. Это может быть полезно для более детального контроля порядка обработки событий, особенно в сложных сценариях или при тестировании. По умолчанию эта опция часто отключена, и события обрабатываются немедленно.
Что попробовать дальше
Phaser предлагает гибкий арсенал для работы с клавиатурой: используйте глобальные события keydown для отладки, именованные события (вроде keydown-A) для разовых действий и дискретный опрос через addKey для непрерывных процессов, таких как движение. Не забывайте про контекст this при вызове stopListeners(). Для экспериментов попробуйте создать систему "комбо-ударов", отслеживая последовательность событий keydown для разных клавиш, или реализуйте ускорение персонажа, когда состояние клавиши isDown проверяется в update вместе с увеличением скорости.
