О чем этот пример
В игровом интерфейсе и визуальных эффектах часто требуется показывать только часть изображения. Phaser предоставляет мощный метод `setCrop()`, позволяющий обрезать текстуру спрайта в реальном времени. Эта статья покажет, как использовать динамическое кадрирование для создания интерактивных элементов, прогресс-баров, анимаций открытия или эффектов "взгляда через объектив". Вы научитесь управлять областью отображения текстуры и визуализировать границы кадрирования.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
offset;
graphics;
bob;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('pic', 'assets/sprites/hotdog.png');
}
create ()
{
this.add.image(400, 300, 'pic').setAlpha(0.3).setScale(2);
this.bob = this.add.image(400, 300, 'pic').setScale(2);
this.graphics = this.add.graphics();
const cropRect = new Phaser.Geom.Rectangle(0, 0, 100, 40);
this.bob.setCrop(cropRect);
this.offset = this.bob.getTopLeft();
this.input.on(Phaser.Input.Events.POINTER_MOVE, pointer =>
{
this.bob.setCrop(
(pointer.x - this.offset.x - cropRect.width) / 2,
(pointer.y - this.offset.y - cropRect.height) / 2,
cropRect.width,
cropRect.height
);
});
}
update ()
{
this.graphics.clear();
this.graphics.lineStyle(1, 0x00ff00);
this.graphics.strokeRect(this.offset.x + (this.bob._crop.x * 2), this.offset.y + (this.bob._crop.y * 2), this.bob._crop.width * 2, this.bob._crop.height * 2);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d88',
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка и подготовка сцены
В методе preload загружается изображение, которое будет использоваться для демонстрации. В create создается фон и основной спрайт для кадрирования.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('pic', 'assets/sprites/hotdog.png');
}
create ()
{
// Полупрозрачный фон для наглядности
this.add.image(400, 300, 'pic').setAlpha(0.3).setScale(2);
// Основной спрайт, который будем кадрировать
this.bob = this.add.image(400, 300, 'pic').setScale(2);
// Графический слой для отрисовки рамки
this.graphics = this.add.graphics();
}
Создание и применение начального кадрирования
Кадрирование определяет прямоугольную область текстуры, которая будет видна. Объект Phaser.Geom.Rectangle задает начальные координаты (x, y) и размеры (width, height) этой области. Важно: координаты кадрирования относятся к исходной текстуре, а не к масштабированному спрайту на сцене.
const cropRect = new Phaser.Geom.Rectangle(0, 0, 100, 40);
this.bob.setCrop(cropRect);
Метод getTopLeft() возвращает мировые координаты верхнего левого угла спрайта. Они нужны для корректного расчета позиции рамки кадрирования в методе update, так как setCrop работает с координатами текстуры.
this.offset = this.bob.getTopLeft();
Интерактивное изменение кадра
Чтобы кадрирование реагировало на движение мыши, подписываемся на событие POINTER_MOVE. В обработчике вычисляются новые координаты кадра. Координаты указателя переводятся в систему координат текстуры: из мировых координат курсора вычитается смещение спрайта (this.offset) и половина размеров кадра, а результат делится на масштаб спрайта (в данном случае 2). Так мы получаем координаты верхнего левого угла нового кадра для текстуры.
this.input.on(Phaser.Input.Events.POINTER_MOVE, pointer =>
{
this.bob.setCrop(
(pointer.x - this.offset.x - cropRect.width) / 2,
(pointer.y - this.offset.y - cropRect.height) / 2,
cropRect.width,
cropRect.height
);
});
Визуализация границ кадрирования
Для наглядности в методе update рисуется зеленая рамка, показывающая текущую область кадрирования в мировых координатах. Каждый кадр графика очищается, задается стиль линии и рисуется прямоугольник. Координаты и размеры для рамки берутся из внутреннего свойства _crop спрайта и конвертируются обратно в мировые координаты с учетом масштаба и смещения.
update ()
{
this.graphics.clear();
this.graphics.lineStyle(1, 0x00ff00);
this.graphics.strokeRect(
this.offset.x + (this.bob._crop.x * 2),
this.offset.y + (this.bob._crop.y * 2),
this.bob._crop.width * 2,
this.bob._crop.height * 2
);
}
Конфигурация игры и запуск
Стандартная конфигурация игры. Обратите внимание на pixelArt: true, который отключает сглаживание текстур, что полезно для пиксель-арт графики.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d88',
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Метод setCrop — это гибкий инструмент для управления отображением текстур. Он открывает возможности для создания нестандартных UI-элементов (например, заполняемых шкал), анимаций (постепенное проявление), игровых механик (ограничение обзора) или мини-карт. Попробуйте изменить размер кадра cropRect, привязать его не к курсору, а к положению другого игрового объекта, или анимировать кадрирование с помощью таймлайнов Tween для создания плавных эффектов открытия/закрытия.
