О чем этот пример
Эффект растровых полос — классический элемент демосцены, который создаёт ощущение динамики и глубины. Этот пример показывает, как используя всего один спрайт, группу объектов и твины в Phaser, можно оживить статичную картинку, превратив её в гипнотизирующую анимацию. Вы научитесь управлять порядком отрисовки, применять цветовые фильтры и создавать синхронизированные циклические движения — техники, полезные для создания меню, заставок или фоновых эффектов в вашей игре.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('raster', 'assets/demoscene/raster-bw-64.png');
}
create ()
{
const group = this.add.group();
group.createMultiple({ key: 'raster', repeat: 8 });
let ci = 0;
const colors = [ 0xef658c, 0xff9a52, 0xffdf00, 0x31ef8c, 0x21dfff, 0x31aade, 0x5275de, 0x9c55ad, 0xbd208c ];
const _this = this;
group.children.forEach(child =>
{
child.x = 100;
child.y = 300;
child.depth = 9 - ci;
child.tint = colors[ci];
ci++;
_this.tweens.add({
targets: child,
x: 700,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut',
duration: 1500,
delay: 100 * ci
});
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов и настройка сцены
Вся работа начинается в методе preload. Здесь мы загружаем единственное изображение, которое будет использоваться для создания всех полос. Важно установить базовый URL для загрузчика, чтобы корректно подгрузить ассет из репозитория с примерами.
preload()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('raster', 'assets/demoscene/raster-bw-64.png');
}
После загрузки Phaser автоматически перейдёт к методу create, который является точкой инициализации игровой логики. Конфигурация игры задаётся в объекте config, где определяется тип рендерера, размеры холста и класс основной сцены.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Создание группы и настройка спрайтов
В методе create первым делом создаётся группа (Group). Группы в Phaser — это мощный инструмент для управления коллекциями игровых объектов. С помощью метода createMultiple мы создаём несколько копий одного спрайта.
const group = this.add.group();
group.createMultiple({ key: 'raster', repeat: 8 });
Параметр repeat: 8 указывает, что нужно создать 8 дополнительных спрайтов (плюс один исходный), итого 9 объектов. Далее определяется палитра цветов в HEX-формате, которая будет применена к полосам.
Затем в цикле forEach настраивается каждый спрайт в группе. Ключевые моменты:
- Позиция `xиy` задаётся одинаковой для всех, создавая начальное вертикальное выравнивание.
- Свойство depth управляет порядком отрисовки (z-index). Значение 9 - ci гарантирует, что первая созданная полоса (с индексом 0) будет иметь глубину 9 и отрисуется поверх остальных, создавая иллюзию слоёв.
: Свойству tint присваивается цвет из массива, эффективно окрашивая монохромный спрайт.
let ci = 0;
const colors = [ 0xef658c, 0xff9a52, 0xffdf00, 0x31ef8c, 0x21dfff, 0x31aade, 0x5275de, 0x9c55ad, 0xbd208c ];
group.children.forEach(child =>
{
child.x = 100;
child.y = 300;
child.depth = 9 - ci;
child.tint = colors[ci];
ci++;
// Твин будет добавлен здесь
});
Анимация с помощью системы твинов
Сердце эффекта — система твинов Phaser (Tweens). Для каждого спрайта в том же цикле создаётся анимация движения.
_this.tweens.add({
targets: child,
x: 700,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut',
duration: 1500,
delay: 100 * ci
});
Разберём параметры этого твина:
- targets: объект, который будет анимирован (наш спрайт child).
- x: 700: конечная координата по оси X.
- yoyo: true: после достижения конечной точки анимация проиграется в обратном порядке.
- repeat: -1: анимация повторяется бесконечно.
- ease: 'Sine.easeInOut': функция плавности, которая обеспечивает мягкое ускорение и замедление.
- duration: 1500: длительность одного цикла (вперед или назад) в миллисекундах.
- delay: 100 * ci: задержка перед стартом анимации. Это ключевой параметр! Умножение на индекс ci создаёт эффект «волны», где каждая следующая полоса начинает движение чуть позже предыдущей.
Обратите внимание на использование _this = this. Это необходимо, потому что внутри callback-функции forEach контекст this был бы другим. Мы сохраняем ссылку на экземпляр сцены, чтобы иметь доступ к this.tweens.
Принцип работы итогового эффекта
В результате всех этих действий мы получаем синхронизированную анимацию. Девять вертикальных полос, окрашенных в разные цвета и расположенных в определённом порядке по глубине, начинают движение с задержкой. Они движутся от X=100 до X=700 и обратно по плавной синусоидальной траектории.
Из-за разницы в delay и одинаковой duration создаётся перспектива: полосы никогда не выстраиваются в одну линию, а постоянно образуют движущиеся узоры. Эффект глубины усиливается за счёт свойства depth — более «близкие» к зрителю полосы (с большим значением depth) перекрывают дальние.
Использование одного графического ассета (raster) с последующим окрашиванием через tint — это оптимизационный приём. Он позволяет создать разноцветную анимацию, загрузив лишь одну текстуру в видеопамять, что положительно сказывается на производительности.
Что попробовать дальше
Этот пример — отличная основа для экспериментов. Попробуйте изменить массив colors на свою палитру. Поиграйте с параметрами твина: замените ease на Cubic, Quad или Back для более резкого или «пружинящего» движения. Измените оси анимации: заставьте полосы двигаться по вертикали (`y) или по диагонали. Добавьте вращение (angle) или масштабирование (scale`) в твин для более сложных визуальных эффектов. Наконец, вы можете реагировать на клик мыши, перезапуская анимацию или динамически создавая новые полосы.
