О чем этот пример

Визуализация функций плавности — мощный инструмент для понимания физики и "ощущения" движения в вашей игре. Вместо того чтобы подбирать анимации наугад, вы можете буквально увидеть, как объект будет ускоряться или замедляться. Эта статья разбирает пример из официальной документации Phaser, который строит графики для квадратичных функций плавности `quad.in`, `quad.out` и `quad.inout`. Вы научитесь не только применять эти функции, но и создавать визуализатор для тестирования любого типа easing, что сэкономит часы настройки анимаций.

Версия 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/background-crt.jpg');
    }

    create ()
    {
        this.add.image(400, 300, 'bg').setScale(0.78);

        this.add.text(400, 28, 'Quadratic Ease').setColor('#00ff00').setFontSize(32).setShadow(2, 2).setOrigin(0.5, 0);

        const types = [ 'quad.in', 'quad.out', 'quad.inout' ];
        let type = 0;
        let tween;

        const label = this.add.text(400, 530).setColor('#00ff00').setFontSize(22).setShadow(1, 1).setOrigin(0.5, 0).setAlign('center');

        const graph = this.add.graphics();
        const rect = this.add.rectangle(100, 400, 2, 2, 0x00ff00);
        const rt = this.add.renderTexture(400, 300, 800, 600);

        const graphEase = () => {

            if (tween)
            {
                tween.stop();
            }

            rt.clear();

            graph.clear();
            graph.lineStyle(3, 0x00ff00);
            graph.beginPath();

            rect.setPosition(50, 450);

            label.setText([
                types[type],
                'Click to change type'
            ]);

            tween = this.tweens.add({
                targets: rect,
                x: { value: 750, ease: 'linear' },
                y: { value: 100, ease: types[type] },
                duration: 4000,
                onUpdate: (tween, target, key) => {
                    if (key === 'x')
                    {
                        rt.draw(rect);
                        graph.lineTo(rect.x, rect.y);
                    }
                },
                onComplete: () => {
                    graph.stroke();
                }
            });
        }

        this.input.on('pointerdown', () => {

            type++;

            if (type === types.length)
            {
                type = 0;
            }

            graphEase();

        });

        graphEase();
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#000000',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Анализ сцены и загрузки ресурсов

Класс Example расширяет Phaser.Scene — стандартный подход для создания сцены в Phaser. В методе preload загружается фоновое изображение. Обратите внимание на использование setBaseURL — это удобно, когда все ресурсы лежат в одной базовой директории.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/tweens/background-crt.jpg');

Подготовка визуальных элементов

В методе create сначала добавляется фон и заголовок. Затем создаются ключевые объекты для визуализации: - graph: объект Graphics для отрисовки линии графика. - rect: зеленый прямоугольник 2x2 пикселя, который будет "пером", оставляющим след. - rt: RenderTexture (текстура для рендеринга), на которую будет копироваться движение прямоугольника, создавая устойчивый след. Также создается текстовый элемент label для отображения текущего типа easing.

const graph = this.add.graphics();
const rect = this.add.rectangle(100, 400, 2, 2, 0x00ff00);
const rt = this.add.renderTexture(400, 300, 800, 600);

Сердце примера: функция `graphEase` и твин

Функция graphEase инициализирует анимацию для текущего выбранного типа плавности. Перед созданием нового твина она очищает текстуру (rt.clear()) и графику (graph.clear()), а также сбрасывает позицию прямоугольника.

Затем создается твин с помощью this.tweens.add. Ключевой момент — использование разных функций плавности для осей X и Y. По оси X движение линейное (ease: 'linear'), что создает равномерную шкалу времени. По оси Y применяется выбранная квадратичная функция (ease: types[type]), которая и формирует график.

tween = this.tweens.add({
    targets: rect,
    x: { value: 750, ease: 'linear' },
    y: { value: 100, ease: types[type] },
    duration: 4000,
    onUpdate: (tween, target, key) => {
        if (key === 'x') {
            rt.draw(rect);
            graph.lineTo(rect.x, rect.y);
        }
    },
    onComplete: () => {
        graph.stroke();
    }
});

Коллбэк onUpdate срабатывает на каждом кадре обновления твина. Проверка if (key === 'x') гарантирует, что отрисовка происходит только один раз за кадр (при обновлении свойства `x). В нем прямоугольник рисуется наRenderTexture, создавая след, а его координаты добавляются в путь объектаGraphics. После завершения твина (onComplete) путь графика обводится линией (graph.stroke()`).

Обработка ввода и переключение типов

Обработчик клика pointerdown перебирает массив типов плавности ['quad.in', 'quad.out', 'quad.inout'] по кругу и каждый раз вызывает graphEase для перестроения графика.

this.input.on('pointerdown', () => {
    type++;
    if (type === types.length) {
        type = 0;
    }
    graphEase();
});

Таким образом, один клик меняет тип функции плавности, и вы можете сразу наблюдать разницу в графике движения.

Конфигурация и запуск игры

Стандартная конфигурация игры Phaser 3. Важно, что scene указывает на наш класс Example.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#000000',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Что попробовать дальше

Этот пример — отличная отправная точка для создания собственного инструмента отладки анимаций. Вы можете расширить массив types, добавив другие функции плавности из Phaser (например, cubic, sine, back), чтобы визуально сравнить их. Поэкспериментируйте: измените начальную и конечную точку движения, попробуйте анимировать не rectangle, а спрайт, или добавьте отрисовку оси времени на график. Понимание того, как работает easing, — это шаг от "движущихся картинок" к профессиональной, приятной глазу игровой анимации.