О чем этот пример
При разработке игр с перетаскиваемыми элементами часто возникает необходимость, чтобы перемещаемый объект отображался поверх остальных. Это важно для удобства игрока и визуальной ясности. В примере на Phaser мы реализуем механизм перетаскивания карт, где выбранная карта будет автоматически подниматься на верхний уровень отображения. Этот подход применим в карточных играх, пазлах, редакторах и любых интерфейсах с перекрывающимися элементами.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/skies/casinotable.png');
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
}
create ()
{
this.add.image(400, 300, 'bg');
this.add.text(16, 16, 'Bring to Top on Drag').setFontSize(24).setShadow(1, 1);
// Create a stack of random cards
const frames = this.textures.get('cards').getFrameNames();
Phaser.Utils.Array.Shuffle(frames);
let x = 140;
let y = 180;
for (let i = 0; i < 22; i++)
{
const image = this.add.image(x, y, 'cards', frames[i]);
image.setInteractive({ draggable: true });
x += 14;
y += 12;
}
this.input.on('dragstart', function (pointer, gameObject) {
// This will bring the selected gameObject to the top of the list
this.children.bringToTop(gameObject);
}, this);
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ресурсов
В методе preload() мы загружаем фоновое изображение и атлас с картами. Атлас — это текстура, содержащая несколько изображений (спрайтов) в одном файле, что оптимизирует загрузку.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/skies/casinotable.png');
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
}
Метод create() создает фон и заголовок, затем генерирует стопку карт. Для этого мы получаем список кадров (frames) из атласа 'cards' и перемешиваем его с помощью Phaser.Utils.Array.Shuffle. Это обеспечивает случайный порядок карт в стопке.
Создание интерактивных карт
В цикле создается 22 карты с небольшим смещением по осям X и Y, имитируя стопку. Каждая карта — объект Image, который мы делаем перетаскиваемым с помощью setInteractive({ draggable: true }).
for (let i = 0; i < 22; i++)
{
const image = this.add.image(x, y, 'cards', frames[i]);
image.setInteractive({ draggable: true });
x += 14;
y += 12;
}
Ключевой параметр draggable: true активирует встроенную поддержку перетаскивания в Phaser. Объекты автоматически реагируют на события drag, но для полного контроля мы добавим свои обработчики.
Обработка начала перетаскивания и подъем объекта
Событие dragstart срабатывает, когда игрок начинает перетаскивание. В его обработчике мы вызываем this.children.bringToTop(gameObject), чтобы переместить выбранный объект на верхний уровень в списке отображения сцены.
this.input.on('dragstart', function (pointer, gameObject) {
this.children.bringToTop(gameObject);
}, this);
Метод bringToTop изменяет порядок рендеринга, гарантируя, что перетаскиваемая карта будет поверх всех других объектов в этой сцене. Контекст this передается как третий аргумент, чтобы мы могли обратиться к this.children внутри функции.
Обновление позиции при перетаскивании
Событие drag происходит непрерывно при движении мыши или касании. Обработчик получает координаты dragX и dragY, которые соответствуют текущей позиции указателя. Мы просто присваиваем их свойствам `xиy` перетаскиваемого объекта.
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
});
Это обеспечивает плавное перемещение карты вслед за курсором. Phaser автоматически обрабатывает физику и коллизии, но в данном примере они не используются.
Что попробовать дальше
Мы реализовали базовый механизм перетаскивания с подъемом объекта на верхний слой. Этот подход прост, но эффективен для многих игровых сценариев. Для экспериментов попробуйте: добавить физические тела через this.physics.add.image для реалистичного движения, ограничить область перетаскивания или реализовать сброс карты в определенную зону с проверкой коллизий. Это отличная основа для карточных игр или редакторов уровней.
