Phaser — это игровая библиотека для JavaScript, построенная на событийно-ориентированной архитектуре. Управление событиями в Phaser позволяет реагировать на действия пользователя, изменения состояния игры и внутренние события движка. События могут исходить от игровых объектов, сцен и систем Phaser, таких как таймеры, физические коллизии или ввод с клавиатуры.
Все события обрабатываются с помощью подписок,
реализованных через методы on, once и
off. Они позволяют:
on(event, callback, context) — подписка на событие.
Вызывается каждый раз, когда событие происходит.once(event, callback, context) — подписка на
одноразовое событие. После первого вызова подписка автоматически
снимается.off(event, callback, context) — отписка от события,
предотвращающая дальнейшие вызовы.Контекст (context) используется для
привязки значения this внутри функции-обработчика.
Сцена (Phaser.Scene) является основным контейнером для
логики игры и поддерживает собственный событийный
эмиттер. Основные события сцены включают:
preload — происходит до загрузки всех ассетов.create — вызывается после загрузки ресурсов и
подготовки сцены.update — вызывается на каждом кадре.shutdown — при завершении сцены, для очистки
ресурсов.destroy — окончательная очистка сцены из памяти.Пример подписки на событие сцены:
class MyScene extends Phaser.Scene {
constructor() {
super({ key: 'MyScene' });
}
create() {
this.events.on('shutdown', this.onShutdown, this);
}
onShutdown() {
console.log('Сцена завершена');
}
}
Использование событий сцены позволяет управлять жизненным циклом объектов и корректно освобождать ресурсы.
Любой объект, созданный через this.add или физический
объект (this.physics.add), может генерировать события.
Наиболее часто используемые события:
pointerdown / pointerup /
pointermove — для обработки ввода с мыши или сенсорного
экрана.drag / dragstart / dragend —
для интерактивного перетаскивания объектов.over / out — события наведения
курсора.Пример обработки клика по спрайту:
const sprite = this.add.sprite(400, 300, 'player');
sprite.setInteractive();
sprite.on('pointerdown', () => {
console.log('Спрайт кликнут');
});
Использование метода setInteractive() обязательно для
того, чтобы объект начал реагировать на указательные события.
Phaser предоставляет две физические системы: Arcade Physics и Matter.js, каждая из которых имеет собственные события.
Arcade Physics поддерживает события коллизий:
collide — когда два объекта сталкиваются.overlap — когда объекты перекрываются, без физического
воздействия.Пример обработки коллизии:
this.physics.add.collider(player, walls, () => {
console.log('Игрок столкнулся со стеной');
});
Matter.js поддерживает более сложные события, такие
как collisionstart, collisionactive,
collisionend:
this.matter.world.on('collisionstart', (event) => {
event.pairs.forEach(pair => {
console.log('Началась коллизия между', pair.bodyA.label, 'и', pair.bodyB.label);
});
});
Phaser использует встроенный класс
Phaser.Events.EventEmitter, который позволяет создавать
собственные события и подписки. Это удобно для
организации модульного кода и уведомления разных систем игры о
происходящих изменениях.
Пример создания собственного эмиттера:
const emitter = new Phaser.Events.EventEmitter();
emitter.on('scoreChanged', (newScore) => {
console.log('Новый счет:', newScore);
});
emitter.emit('scoreChanged', 100);
Подобная архитектура позволяет легко добавлять новые системы взаимодействия, не нарушая существующий код.
Правильное управление подписками критически важно для предотвращения утечек памяти. Для игровых объектов и сцен рекомендуется:
once для одноразовых событий.off)
или завершении сцены (shutdown).this.Пример безопасной отписки:
this.events.off('update', this.onUpdate, this);
Для групп объектов или сложных сцен можно хранить все подписки в массиве и массово очищать их при завершении.
Phaser предоставляет отдельные системы для клавиатуры, мыши и
геймпадов. Методы this.input.keyboard.on или
this.input.gamepad.on позволяют подписываться на события
нажатий клавиш и кнопок контроллера.
Пример обработки клавиши:
this.input.keyboard.on('keydown-SPACE', () => {
console.log('Пробел нажат');
});
События ввода обеспечивают асинхронное реагирование на действия пользователя без необходимости проверять состояние на каждом кадре.
Для событий, которые могут срабатывать очень часто (например,
pointermove или update), полезно использовать
дебаунс или throttle. Это
предотвращает перегрузку логики игры и снижает нагрузку на CPU.
Пример простого throttling:
let lastCall = 0;
sprite.on('pointermove', (pointer) => {
const now = Date.now();
if (now - lastCall > 50) {
lastCall = now;
console.log('Движение указателя обработано');
}
});
Эта структура позволяет создавать гибкие и масштабируемые игры, где каждая часть системы реагирует на события независимо, сохраняя чистоту кода и управляемость.