О чем этот пример
Визуальные эффекты — ключ к созданию атмосферы в игре. В этом примере мы разберем, как создать эффект огненного шара, оставляющего за собой след, используя мощный инструмент Phaser — Render Texture. Этот подход позволяет рисовать движущийся объект на текстуре в реальном времени, создавая иллюзию плавного шлейфа, что идеально подходит для заклинаний, выстрелов или движения с частицами.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
player;
fireFX;
fireball;
rt;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('dude', 'assets/sprites/phaser-dude.png');
this.load.image('fire', 'assets/particles/muzzleflash3.png');
}
create ()
{
this.rt = this.make.renderTexture({ x: 0, y: 0, width: 800, height: 600 });
this.player = this.add.image(100, 300, 'dude');
this.fireball = this.add.follower(null, 50, 350, 'fire');
this.fireFX = this.tweens.add({
targets: this.fireball,
scaleX: 3,
scaleY: 3,
alpha: 0,
duration: 300,
ease: 'Cubic.easeOut',
onComplete: function () { this.rt.clear().render(); this.fireball.alpha = 0; },
paused: true
});
this.fireFX.setCallback('onUpdate', this.draw, [], this);
this.input.on('pointerdown', pointer =>
{
this.generate(pointer.x, pointer.y);
}, this);
}
generate (x, y)
{
this.fireball.setPosition(this.player.x, this.player.y).setScale(0.5).setAlpha(1);
const curve = new Phaser.Curves.Line(new Phaser.Math.Vector2(this.player.x, this.player.y), new Phaser.Math.Vector2(x, y));
this.fireball.setPath(curve);
this.fireball.startFollow(300);
this.fireFX.restart();
}
draw ()
{
this.rt.draw(this.fireball).render();
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example,
width: 800,
height: 600
};
const game = new Phaser.Game(config);
Инициализация сцены и загрузка ассетов
Как и в любой сцене Phaser, мы начинаем с объявления переменных класса и загрузки ресурсов.
class Example extends Phaser.Scene
{
player;
fireFX;
fireball;
rt;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('dude', 'assets/sprites/phaser-dude.png');
this.load.image('fire', 'assets/particles/muzzleflash3.png');
}
Здесь player — спрайт персонажа, fireball — сам огненный шар, fireFX — твин для анимации его исчезновения, а rt — самая важная часть, объект RenderTexture. В preload загружаются два изображения: спрайт персонажа и текстура огня для шара.
Создание объектов и настройка анимации
В методе create мы создаем все необходимые игровые объекты и настраиваем их взаимодействие.
create ()
{
this.rt = this.make.renderTexture({ x: 0, y: 0, width: 800, height: 600 });
this.player = this.add.image(100, 300, 'dude');
this.fireball = this.add.follower(null, 50, 350, 'fire');
Сначала создается RenderTexture размером с холст (800x600). Персонаж (player) добавляется как обычное изображение. Объект fireball создается как follower — специальный спрайт, который может следовать по заданному пути (curve). Изначально его путь null, и он позиционируется вне экрана.
this.fireFX = this.tweens.add({
targets: this.fireball,
scaleX: 3,
scaleY: 3,
alpha: 0,
duration: 300,
ease: 'Cubic.easeOut',
onComplete: function () { this.rt.clear().render(); this.fireball.alpha = 0; },
paused: true
});
this.fireFX.setCallback('onUpdate', this.draw, [], this);
Создается твин fireFX. Он будет увеличивать шар в 3 раза и делать его полностью прозрачным за 300 миллисекунд с плавным ускорением (Cubic.easeOut). Ключевой параметр paused: true — твин не запустится сам по себе. В колбэке onComplete текстура rt очищается методом .clear().render(), а альфа-канал шара сбрасывается в 0, чтобы скрыть его.
Самая важная строка — this.fireFX.setCallback('onUpdate', this.draw, [], this). Она связывает метод draw с событием onUpdate твина. Это значит, что draw будет вызываться на каждом кадре анимации твина.
Запуск эффекта по клику
Эффект запускается при клике мыши. Обработчик события pointerdown вызывает метод generate, передавая координаты клика.
this.input.on('pointerdown', pointer =>
{
this.generate(pointer.x, pointer.y);
}, this);
Генерация пути и запуск анимации
Метод generate отвечает за инициализацию полета огненного шара от персонажа к точке клика.
generate (x, y)
{
this.fireball.setPosition(this.player.x, this.player.y).setScale(0.5).setAlpha(1);
const curve = new Phaser.Curves.Line(new Phaser.Math.Vector2(this.player.x, this.player.y), new Phaser.Math.Vector2(x, y));
this.fireball.setPath(curve);
this.fireball.startFollow(300);
this.fireFX.restart();
}
1. fireball позиционируется на персонаже, его масштаб сбрасывается до 0.5, а прозрачность — до 1 (полностью видимый).
2. Создается линейная кривая (Phaser.Curves.Line) от позиции персонажа до точки клика.
3. Эта кривая задается как путь для fireball с помощью setPath, и начинается движение по нему со скоростью 300 пикселей в секунду (startFollow(300)).
4. Запускается (или перезапускается) твин fireFX методом .restart(). Именно он отвечает за анимацию увеличения и затухания.
Магия Render Texture
Метод draw — это сердце эффекта следа. Он вызывается на каждом обновлении твина fireFX.
draw ()
{
this.rt.draw(this.fireball).render();
}
Вот что происходит:
1. Метод this.rt.draw(this.fireball) рисует текущий кадр спрайта fireball (с его актуальной позицией, масштабом и поворотом) на RenderTexture.
2. Метод .render() применяет это рисование.
Поскольку твин выполняется 300 мс, а draw вызывается много раз за это время, на текстуре остается "отпечаток" шара на всех промежуточных позициях его движения и трансформации. Так создается плавный след. Очистка текстуры (rt.clear()) в колбэке onComplete твина стирает след, готовя текстуру к следующему выстрелу.
Что попробовать дальше
Использование связки RenderTexture и твина с колбэком onUpdate — элегантный и производительный способ создания эффектов следа, шлейфа или временных отпечатков в Phaser 3. Для экспериментов попробуйте изменить изображение fire на спрайт-лист для анимированного следа, добавьте размытие или цветовые фильтры к rt, или создайте несколько следов разного цвета, используя отдельные RenderTexture для каждого.
