О чем этот пример
Создание анимаций — неотъемлемая часть разработки игр. Простое перемещение объекта из точки A в точку B часто выглядит искусственно и скучно. Именно здесь на помощь приходят easing-функции, или функции плавности. Они управляют скоростью анимации, придавая ей естественность, упругость или другой желаемый характер. В этой статье мы разберем официальный пример из Phaser, демонстрирующий три варианта круговой (Circular) функции плавности: `Circ.in`, `Circ.out` и `Circ.inOut`. Вы поймете, как работает система твинов (tweens) в Phaser и как с помощью одного параметра `ease` кардинально изменить восприятие одной и той же анимации.
Версия 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/tweens/space.png');
this.load.image('ufo1', 'assets/tweens/ufo1.png');
this.load.image('ufo2', 'assets/tweens/ufo2.png');
this.load.image('ufo3', 'assets/tweens/ufo3.png');
}
create ()
{
this.add.image(400, 300, 'bg');
this.add.text(20, 20, 'Circular Ease').setFontSize(32).setShadow(2, 2);
this.add.text(750, 70, 'Circ.in').setShadow(2, 2).setOrigin(1, 0);
this.add.text(750, 255, 'Circ.out').setShadow(2, 2).setOrigin(1, 0);
this.add.text(750, 440, 'Circ.inOut').setShadow(2, 2).setOrigin(1, 0);
const ufo1 = this.add.image(100, 140, 'ufo1');
const ufo2 = this.add.image(100, 325, 'ufo2');
const ufo3 = this.add.image(100, 510, 'ufo3');
this.tweens.add({
targets: ufo1,
x: 700,
duration: 2000,
repeat: -1,
hold: 500,
repeatDelay: 500,
ease: 'circ.in'
});
this.tweens.add({
targets: ufo2,
x: 700,
duration: 2000,
repeat: -1,
hold: 500,
repeatDelay: 500,
ease: 'circ.out'
});
this.tweens.add({
targets: ufo3,
x: 700,
duration: 2000,
repeat: -1,
hold: 500,
repeatDelay: 500,
ease: 'circ.inout'
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ресурсов
Код начинается с определения класса сцены Example. В методе preload() загружаются все необходимые изображения: фон (bg) и три спрайта НЛО разных цветов (ufo1, ufo2, ufo3). Важно отметить, что базовый URL задается через this.load.setBaseURL. Это удобно, если все ресурсы хранятся в одном месте.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/tweens/space.png');
this.load.image('ufo1', 'assets/tweens/ufo1.png');
В методе create() сначала добавляется фон и текстовые подписи для заголовка и каждого типа анимации. Обратите внимание на метод .setOrigin(1, 0) для текстов справа — он устанавливает точку привязки текста в его правый верхний угол, что упрощает выравнивание по правому краю.
this.add.text(750, 70, 'Circ.in').setShadow(2, 2).setOrigin(1, 0);
Затем создаются и размещаются по вертикали три спрайта НЛО, которые станут целями для наших анимаций.
const ufo1 = this.add.image(100, 140, 'ufo1');
Создание твинов: основа анимации
Сердце примера — вызовы this.tweens.add(). Твин — это анимация, изменяющая свойства одного или нескольких объектов (targets) с течением времени.
Базовый конфиг твина включает:
* targets: объект или массив объектов для анимации.
* x: 700: целевое значение свойства (перемещение по горизонтали).
* duration: длительность анимации в миллисекундах.
* repeat: -1: бесконечное повторение.
* hold: пауза в миллисекундах, когда цель достигла конечного значения.
* repeatDelay: задержка перед началом повторения анимации.
this.tweens.add({
targets: ufo1,
x: 700,
duration: 2000,
repeat: -1,
hold: 500,
repeatDelay: 500,
ease: 'circ.in'
});
Ключевой параметр, отличающий три анимации в примере, — ease. Именно он определяет, как будет меняться скорость движения НЛО от начала к концу.
Круговая плавность (Circular Ease): разбираем варианты
Круговая функция плавности основана на математической функции, производной от уравнения окружности. Она создает эффект движения по дуге. В Phaser доступны три её модификации, которые наглядно показаны в примере.
**Circ.in** — анимация начинается медленно и резко ускоряется к концу. Визуально это похоже на объект, который "падает" под действием силы тяжести. В коде это задается строкой ease: 'circ.in'.
**Circ.out** — полная противоположность: объект стартует очень быстро, а затем плавно и медленно "зависает" в конечной точке. Это создает ощущение инерции или мягкой посадки. Задается параметром ease: 'circ.out'.
**Circ.inOut** — комбинированный вариант. Анимация плавно ускоряется в первой половине пути и так же плавно замедляется во второй. Это самый сбалансированный и естественный для многих процессов тип движения. В коде используется ease: 'circ.inout' (обратите внимание на регистр).
ease: 'circ.inout'
Конфигурация игры и запуск
За пределами класса сцены определяется объект конфигурации игры config. В нем задаются тип рендерера, размеры холста, цвет фона, элемент DOM для встраивания и класс основной сцены.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
Инициализация игры происходит созданием нового экземпляра Phaser.Game, в который передается конфигурация. После этого Phaser берет на себя управление жизненным циклом сцены (preload, create, update).
const game = new Phaser.Game(config);
Что попробовать дальше
Использование easing-функций — простой, но мощный способ оживить игровой мир. Как показал пример, достаточно изменить одну строку с параметром ease, чтобы придать анимации совершенно новое физическое ощущение.
**Идеи для экспериментов:**
1. Поменяйте тип функции на другие встроенные (например, 'sine', 'bounce', 'back') и понаблюдайте за разницей.
2. Создайте твин, анимирующий несколько свойств одновременно (например, `x,yиangle`) с разными функциями плавности.
3. Попробуйте применить yoyo: true вместо hold и repeatDelay, чтобы объект возвращался по той же траектории.
