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

При создании сложных анимаций в Phaser часто требуется выполнить дополнительные действия именно в момент старта tween-анимации. Например, сделать объект видимым, воспроизвести звук или обновить интерфейс. Встроенный коллбэк `onStart` в конфигурации Tween позволяет сделать это точно и без костылей. В этой статье разберем, как правильно настроить и использовать `onStart` и `onStartParams`, чтобы связать запуск анимации с вашей игровой логикой. Это особенно полезно для синхронизации визуальных эффектов с геймплеем.

Версия 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('block', 'assets/sprites/block.png');
    }

    create()
    {
        var marker = this.add.image(100, 100, 'block').setAlpha(0.3);
        var image = this.add.image(100, 100, 'block').setAlpha(0);

        var tween = this.tweens.add({
            targets: image,
            x: 600,
            ease: 'Power1',
            duration: 3000,
            paused: true,
            onStart: this.onStartHandler,
            onStartParams: [image]
        });

        this.input.once('pointerdown', function ()
        {

            tween.play();

        });
    }

    //  The callback is always sent a reference to the Tween as the first argument and the targets as the second,
    //  then whatever you provided in the onStartParams array follows
    onStartHandler(tween, targets, gameObject)
    {
        console.log(arguments);

        gameObject.setAlpha(1);
    }
}

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 — это объект, управляющий плавной анимацией свойств одного или нескольких целевых объектов (targets) за указанное время. У каждого tween есть жизненный цикл с ключевыми событиями, на которые можно подписаться. Одно из таких событий — onStart. Оно срабатывает один раз, непосредственно перед началом интерполяции свойств, даже если tween был запущен из паузы (paused: true).

Это отличает onStart от, например, onActive, который может срабатывать при каждом возобновлении анимации. onStart идеально подходит для одноразовой инициализации, связанной со стартом движения.

Разбор примера: Подготовка сцены и объектов

В примере создается простая сцена с двумя спрайтами — маркером и основным изображением. Маркер полупрозрачный и показывает начальную точку. Основное изображение изначально полностью прозрачное (setAlpha(0)).

preload() {
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('block', 'assets/sprites/block.png');
}

create() {
    var marker = this.add.image(100, 100, 'block').setAlpha(0.3);
    var image = this.add.image(100, 100, 'block').setAlpha(0);
}

Ключевой момент: tween создается в состоянии паузы (paused: true). Это частая практика, когда анимация должна запуститься по внешнему событию (клику мыши в данном случае).

Конфигурация Tween с коллбэком `onStart`

Коллбэк onStart задается прямо в конфигурационном объекте tween. Вместе с ним через массив onStartParams можно передать дополнительные аргументы, которые будут подставлены в функцию-обработчик после стандартных параметров.

var tween = this.tweens.add({
    targets: image, // Целевой объект для анимации
    x: 600,         // Конечная координата X
    ease: 'Power1', // Функция плавности
    duration: 3000, // Длительность анимации в миллисекундах
    paused: true,   // Создать, но не запускать сразу
    onStart: this.onStartHandler, // Ссылка на функцию-обработчик
    onStartParams: [image] // Дополнительный аргумент для обработчика
});

Обратите внимание: onStartParams — это массив. В данном случае мы передаем в него ссылку на тот же объект image, который является target. Это нужно для удобства доступа внутри обработчика.

Обработчик события и его параметры

Phaser автоматически передает в функцию-обработчик onStart два первых аргумента: ссылку на сам объект tween и массив целевых объектов. Затем идут аргументы из вашего массива onStartParams.

onStartHandler(tween, targets, gameObject) {
    console.log(arguments); // Можно посмотреть все переданные аргументы
    gameObject.setAlpha(1); // Делаем объект полностью видимым
}

В нашем примере: 1. tween — ссылка на созданный нами tween. 2. targets — массив [image]. 3. gameObject — тот самый объект image, который мы передали через onStartParams: [image].

Именно в этот момент, перед началом движения, мы вызываем gameObject.setAlpha(1), чтобы блок стал видимым. Запуск анимации происходит по клику мыши через tween.play().

Запуск анимации по внешнему событию

Tween создан в паузе, поэтому для его старта требуется явный вызов метода play(). В примере это привязано к событию клика (pointerdown).

this.input.once('pointerdown', function () {
    tween.play();
});

Использование once гарантирует, что обработчик сработает только при первом клике. При вызове play() сразу же сработает коллбэк onStartHandler, сделав объект видимым, и только затем начнется анимация перемещения к точке x: 600.

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

Коллбэк onStart — это мощный и точный инструмент для привязки логики инициализации к началу анимации. Он помогает избежать рассинхронизации, когда код подготовки выполняется до или после tween.play(). **Идеи для экспериментов:** 1. Попробуйте передать в onStartParams не сам объект, а его свойство (например, цвет) и менять его в обработчике. 2. Создайте цепочку tween-ов, где onStart второго tween запускается в onComplete первого, и поэкспериментируйте с передачей данных между ними через параметры. 3. Вместо setAlpha в коллбэке запустите частицу (this.add.particles) в стартовой позиции объекта для создания эффекта появления.