О чем этот пример
Анимация изменения размера (scale) объектов — базовая, но мощная техника для оживления игровой сцены. В этом примере мы рассмотрим, как реализовать плавное 'дыхание' спрайтов, увеличивая и уменьшая их масштаб в цикле, используя только метод `update`. Такой подход универсален и подходит для создания эффектов появления, пульсации или простой фоновой анимации без использования сложных систем анимации. Вы научитесь напрямую управлять свойством `scale` в реальном времени.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var config = {
type: Phaser.CANVAS,
parent: 'phaser-example',
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
var atlasFrame;
var singleImage;
var d = 0;
function preload() {
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('atari', 'assets/sprites/atari130xe.png');
this.load.atlas('atlas', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');
}
function create() {
atlasFrame = this.add.image(0, 0, 'atlas', 'dragonwiz');
singleImage = this.add.image(0, 400, 'atari');
atlasFrame.scale = 0;
singleImage.scale = 0;
}
function update() {
if (d === 0)
{
atlasFrame.scale += 0.01;
singleImage.scale += 0.01;
if (singleImage.scale >= 4)
{
d = 1;
}
}
else
{
atlasFrame.scale -= 0.01;
singleImage.scale -= 0.01;
if (singleImage.scale <= 0)
{
d = 0;
}
}
}
Загрузка ресурсов и настройка сцены
В методе preload мы загружаем два типа ресурсов: обычное изображение и атлас (спрайтшит). Обратите внимание, что используется setBaseURL для указания корневой папки с ресурсами.
function preload() {
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('atari', 'assets/sprites/atari130xe.png');
this.load.atlas('atlas', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');
}
После загрузки, в create, мы создаем два спрайта: один (atlasFrame) берет конкретный кадр 'dragonwiz' из атласа, а второй (singleImage) использует обычное изображение 'atari'. Оба спрайта изначально имеют нулевой масштаб, что делает их невидимыми на старте.
function create() {
atlasFrame = this.add.image(0, 0, 'atlas', 'dragonwiz');
singleImage = this.add.image(0, 400, 'atari');
atlasFrame.scale = 0;
singleImage.scale = 0;
}
Логика анимации в методе update
Сердце анимации находится в функции update, которая вызывается на каждом кадре игры. Мы используем простой флаг `d` (direction — направление), чтобы отслеживать, должны ли спрайты увеличиваться или уменьшаться.
function update() {
if (d === 0) {
atlasFrame.scale += 0.01;
singleImage.scale += 0.01;
if (singleImage.scale >= 4) {
d = 1;
}
} else {
atlasFrame.scale -= 0.01;
singleImage.scale -= 0.01;
if (singleImage.scale <= 0) {
d = 0;
}
}
}
Когда `dравен 0, масштаб обоих объектов увеличивается на 0.01 каждый кадр. Как только масштабsingleImageдостигает или превышает 4, флагd` переключается в 1, и начинается фаза уменьшения. При достижении масштабом нуля флаг сбрасывается, и цикл повторяется. Это создает эффект непрерывного пульсирующего роста и сжатия.
Работа со свойством scale
Свойство scale объекта Image в Phaser управляет его однородным масштабированием. Значение 1 соответствует исходному размеру текстуры, 0 делает объект невидимым, а 2 — удваивает его. В нашем примере мы меняем это значение напрямую.
atlasFrame.scale = 0; // Полное сжатие (невидимо)
singleImage.scale += 0.01; // Увеличение на каждом кадре
Важно: изменение scale влияет не только на визуальный размер, но и на физическую область объекта (например, для пересечений), если используется физический движок. В данном примере физика не задействована, поэтому мы работаем только с визуальной частью.
Почему именно update, а не Tween?
Phaser предлагает мощную систему анимаций Tweens для подобных задач. Однако использование update дает полный контроль над логикой на каждом кадре. Это полезно, когда анимация должна реагировать на сложные условия игры (например, менять скорость в зависимости от действий игрока) или быть тесно связанной с другой игровой логикой.
// Альтернатива через Tween могла бы выглядеть так:
// this.tweens.add({
// targets: [atlasFrame, singleImage],
// scale: { from: 0, to: 4 },
// yoyo: true,
// repeat: -1,
// duration: 1000
// });
Прямое управление в update более низкоуровневое и гибкое, но требует ручного управления состоянием (флаг `d). Выбор подхода зависит от требований: для простых повторяющихся анимаций часто удобнееTween, для кастомной логики —update`.
Отладка и контроль скорости
Скорость анимации в данном примере жестко задана значением 0.01, привязанным к частоте кадров. Это может привести к разной скорости на устройствах с разным FPS. Для независимой от частоты кадров анимации нужно использовать время, прошедшее с последнего кадра (delta).
// Пример с использованием delta для независимой от FPS скорости:
function update(time, delta) {
const deltaScale = (0.01 * delta) / 16.67; // 16.67ms ~ 60 FPS
if (d === 0) {
atlasFrame.scale += deltaScale;
singleImage.scale += deltaScale;
// ... остальная логика
}
}
Также полезно выводить текущий масштаб в консоль для отладки:
console.log(`Scale: ${singleImage.scale.toFixed(2)}, Direction: ${d}`);
Что попробовать дальше
Прямое управление свойством scale в методе update — это простой и эффективный способ создания плавной анимации масштабирования. Вы можете экспериментировать: изменить скорость роста и сжатия для каждого спрайта отдельно, добавить случайность в изменение масштаба для эффекта 'дрожания', или привязать анимацию к вводу игрока (например, увеличение при наведении курсора). Для более сложных сценариев изучите this.tweens или систему анимаций createAnimations для пошагового скейлинга спрайтов из атласа.
