О чем этот пример
Создание игрового мира — это не только расстановка готовых спрайтов. Часто нужны объекты со своей логикой и предустановленными свойствами. В этой статье разберем, как создавать собственные классы игровых объектов, наследуясь от стандартных классов Phaser. Это позволяет инкапсулировать логику, повторно использовать код и создавать сложные иерархии сущностей, делая код чище и масштабируемее.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class EnemyRobot extends Phaser.GameObjects.Image {
constructor (scene, x, y)
{
super(scene, x, y);
this.setTexture('contra');
this.setPosition(x, y);
this.setScale(2);
}
}
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('contra', 'assets/pics/contra3.png');
}
function create ()
{
this.children.add(new EnemyRobot(this, 264, 250));
this.children.add(new EnemyRobot(this, 464, 350));
this.children.add(new EnemyRobot(this, 664, 450));
}
Зачем свои классы?
Представьте, что в игре десятки одинаковых врагов. Копировать код настройки для каждого — неэффективно и чревато ошибками. Гораздо лучше описать врага один раз в виде класса, а затем создавать его экземпляры.
Кастомный класс позволяет:
* **Группировать настройки**: Размер, текстура, физические свойства задаются в конструкторе.
* **Добавлять логику**: В дальнейшем в класс можно добавить методы для анимации, стрельбы, получения урона.
* **Упрощать создание**: Инициализация нового врага сводится к одному вызову new.
В примере мы создаем класс EnemyRobot, который является расширением стандартного Phaser.GameObjects.Image.
Создаем класс-наследник
Ключевой момент — использование синтаксиса ES6 class и ключевого слова extends. Это указывает, что наш EnemyRobot будет обладать всеми свойствами и методами игрового изображения (Image).
class EnemyRobot extends Phaser.GameObjects.Image {
constructor (scene, x, y)
{
super(scene, x, y);
this.setTexture('contra');
this.setPosition(x, y);
this.setScale(2);
}
}
Разберем конструктор:
1. `super(scene, x, y);` — Вызов конструктора родительского класса (`Image`). Это обязательный первый шаг. Он регистрирует объект в текущей сцене `scene` и задает его начальные координаты.
2. `this.setTexture('contra');` — Указывает ключ текстуры, загруженной в `preload`. Объект будет отображать эту картинку.
3. `this.setPosition(x, y);` — Явно устанавливает позицию. Хотя она уже передана в `super()`, это хорошая практика для ясности.
4. `this.setScale(2);` — Увеличивает спрайт в 2 раза. Это уже кастомное свойство нашего робота.
Загрузка ассетов и создание игры
Конфигурация игры и загрузка ресурсов остаются стандартными. Обратите внимание, что в preload мы загружаем изображение по ключу 'contra', который затем используем в классе.
function preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('contra', 'assets/pics/contra3.png');
}
Конфиг игры указывает на функции preload и create.
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
Добавляем объекты на сцену
В функции create происходит магия. Мы создаем экземпляры нашего класса и добавляем их в список дочерних объектов сцены через this.children.add(). Каждый робот автоматически получает все заданные в конструкторе свойства.
function create ()
{
this.children.add(new EnemyRobot(this, 264, 250));
this.children.add(new EnemyRobot(this, 464, 350));
this.children.add(new EnemyRobot(this, 664, 450));
}
Важно: new EnemyRobot(this, 464, 350) — здесь первый аргумент this (сцена) передается в конструктор класса. Метод this.children.add() регистрирует объект в системе отображения Phaser.
Что попробовать дальше
Создание собственных классов игровых объектов — фундаментальный шаг к структурированной и мощной кодовой базе в Phaser. Вы не ограничены изображениями: можно наследоваться от Sprite, Container или даже PhysicsImage. Для экспериментов попробуйте добавить в класс метод update() для автоматического движения врага, реализовать параметр здоровья (this.health) или создать иерархию классов (например, базовый Enemy и наследующие от него EnemyRobot и EnemyAlien).
