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

Анимация в играх — это не только движение персонажей. Часто требуется плавно изменять числовые значения: счёт, здоровье, прогресс-бар или таймер. Прямое присваивание выглядит резко и неестественно. В этом примере мы рассмотрим мощный инструмент Phaser — `Tween` для счётчика (`addCounter`). Он позволяет создавать плавные переходы между двумя числами, делая интерфейс и игровую механику визуально приятными и профессиональными. Вы научитесь анимировать любые числовые данные, контролировать процесс и использовать результат в реальном времени.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


var text;
var tween;

class Example extends Phaser.Scene {
    constructor() {
        super();
    }

    create() {
        text = this.add.text(30, 20, '0', { font: '42px Courier', fill: '#00ff00' });

        //  A 'Counter' tween is a special type of tween which doesn't have a target.
        //  Instead it allows you to tween between 2 numeric values. The default values
        //  are 0 to 1, but can be set to anything. You can use the tweened value via
        //  `tween.getValue()` for the duration of the tween.

        tween = this.tweens.addCounter({
            from: 100,
            to: 200,
            duration: 5000,
            yoyo: true
        });
    }

    update() {
        text.setText([
            'Value: ' + tween.getValue(),
            'Progress: ' + tween.totalProgress,
            'Elapsed: ' + tween.totalElapsed,
            'Duration: ' + tween.totalDuration
        ]);
    }
}

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

const game = new Phaser.Game(config);

Что такое Tween-счётчик и зачем он нужен?

Обычный Tween в Phaser привязан к конкретному свойству игрового объекта, например, к координате `xспрайта.Tween-счётчик (addCounter`) — это особый тип твина без явной цели. Вместо изменения свойств объекта он плавно интерполирует (переходит) между двумя заданными числами.

Это идеально для сценариев, где нужно получить изменяющееся во времени число и использовать его самостоятельно. Например: * Плавное увеличение счёта при сборе монет. * Анимация заполнения шкалы здоровья или маны. * Создание плавно меняющегося параметра для шейдера или кастомной графики. * Управление громкостью звука или прозрачностью группы объектов.

Разбор создания счётчика

Вся магия происходит в методе create. Сначала создаётся текстовый объект для отображения значений.

text = this.add.text(30, 20, '0', { font: '42px Courier', fill: '#00ff00' });

Затем создаётся сам твин-счётчик. Ключевой метод — this.tweens.addCounter(config).

tween = this.tweens.addCounter({
    from: 100,
    to: 200,
    duration: 5000,
    yoyo: true
});

Разберём параметры конфигурации: * from: 100 — начальное значение счётчика. * to: 200 — конечное значение. * duration: 5000 — длительность перехода от from к to в миллисекундах (5 секунд). * yoyo: true — опция, заставляющая твин проигрываться в обратном порядке после завершения, создавая цикл (100→200, затем 200→100).

Получение значения и мониторинг прогресса

Созданный твин работает в фоновом режиме. Чтобы использовать его текущее значение, нужно вызвать метод getValue() у объекта твина.

В методе update (вызывается каждый кадр) мы запрашиваем актуальные данные твина и отображаем их. Это демонстрирует, как можно интегрировать анимированное число в логику игры.

text.setText([
    'Value: ' + tween.getValue(), // Текущее число между from и to
    'Progress: ' + tween.totalProgress, // Общий прогресс твина от 0 до 1
    'Elapsed: ' + tween.totalElapsed, // Сколько времени прошло (мс)
    'Duration: ' + tween.totalDuration // Полная длительность цикла (мс)
]);

Важно: totalProgress, totalElapsed и totalDuration учитывают опцию yoyo. При yoyo: true полный цикл длится 10000 мс (5 сек туда + 5 сек обратно).

Практическое применение: плавный счёт

Давайте применим знания на практике. Создадим эффект плавного набора очков. Предположим, игрок заработал 1000 очков, и мы хотим, чтобы цифры на экране увеличивались не скачком, а плавно.

// В момент получения очков
let currentScore = 500;
let newScore = 1500;

// Создаём твин-счётчик от текущего значения к новому
this.scoreTween = this.tweens.addCounter({
    from: currentScore,
    to: newScore,
    duration: 2000, // Анимация за 2 секунды
    onUpdate: (tween) => {
        // Каждый кадр обновляем текст счёта, округляя значение
        this.scoreText.setText(`Score: ${Math.round(tween.getValue())}`);
    },
    onComplete: () => {
        // По завершении гарантированно выставляем точное значение
        currentScore = newScore;
    }
});

Здесь используется callback onUpdate для обновления текста и onComplete для синхронизации логической переменной.

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

Tween-счётчик — это элегантное решение для анимации чисел, которое значительно улучшает пользовательский опыт. Он избавляет от необходимости вручную писать логику интерполяции в update. Для экспериментов попробуйте: добавить repeat для многократного повторения, использовать разные функции плавности (ease) для нелинейного изменения значения (например, ease: 'Power2'), или связать значение счётчика не только с текстом, но и со свойством scale или alpha группы объектов.