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

Анимация объектов — основа динамики в играх. Часто недостаточно просто переместить спрайт — нужно запустить следующее действие: изменить его состояние, воспроизвести звук или начать новую анимацию. Колбэк `onComplete` в системе твинов Phaser решает эту задачу элегантно, позволяя связать завершение анимации с любой логикой вашей игры. В этой статье разберем, как настроить такой колбэк и передать в него параметры для гибкого управления геймплеем.

Версия 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, 300, 'block').setAlpha(0.3);
        var image = this.add.image(100, 300, 'block');

        this.tweens.add({
            targets: image,
            x: 600,
            ease: 'Power1',
            duration: 3000,
            onComplete: this.onCompleteHandler,
            onCompleteParams: [image]
        });
    }

    //  The callback is always sent a reference to the Tween as the first argument and the targets as the second.
    //  Whatever you provided in the onCompleteParams array follows.
    onCompleteHandler(tween, targets, myImage)
    {
        console.log('onCompleteHandler');

        myImage.setScale(2);
    }
}

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

const game = new Phaser.Game(config);

Что такое твин и его колбэк onComplete

Твин (tween) в Phaser — это объект, управляющий плавным изменением свойств цели (например, позиции, прозрачности, масштаба) за заданное время. Метод this.tweens.add() создает и запускает такой твин.

Колбэк onComplete — это функция, которую вы указываете в конфигурации твина. Движок автоматически вызовет ее один раз, когда анимация полностью завершится. Это идеальный момент для выполнения пост-обработки.

Создание базовой анимации с колбэком

Рассмотрим код из примера. В методе create() сцены создаются два спрайта — маркер и подвижное изображение. Для подвижного изображения настраивается твин, который за 3 секунды переместит его по оси X.

Ключевой параметр — onComplete. В него передается ссылка на метод класса сцены this.onCompleteHandler. Phaser вызовет этот метод, когда блок достигнет координаты x=600.

this.tweens.add({
    targets: image,
    x: 600,
    ease: 'Power1',
    duration: 3000,
    onComplete: this.onCompleteHandler, // Указываем функцию-обработчик
    onCompleteParams: [image] // Передаем параметры для обработчика
});

Функция-обработчик и ее параметры

Функция onCompleteHandler объявлена как метод сцены. Phaser всегда вызывает ее с определенными аргументами.

* **Первый аргумент (tween)**: ссылка на сам объект твина, который завершился. Полезно, если нужно его перезапустить или остановить другие связанные твины. * **Второй аргумент (targets)**: массив целей, к которым был применен твин. В нашем случае это массив с одним элементом — спрайтом image. * **Последующие аргументы**: значения, которые вы сами передали в массиве onCompleteParams. В примере мы передали [image], поэтому третьим аргументом (myImage) придет тот же спрайт.

//  The callback is always sent a reference to the Tween as the first argument and the targets as the second.
//  Whatever you provided in the onCompleteParams array follows.
onCompleteHandler(tween, targets, myImage)
{
    console.log('onCompleteHandler');
    // Меняем масштаб переданного спрайта
    myImage.setScale(2);
}

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

Почему важно передавать параметры явно

Вы могли бы обратиться к спрайту image напрямую, если бы он был сохранен в переменной класса. Однако явная передача через onCompleteParams делает код более универсальным и надежным.

Представьте, что у вас несколько анимаций для разных объектов, завершающихся одним обработчиком. Параметры позволяют понять, с каким именно объектом нужно работать. Это также помогает избежать проблем с областью видимости (this), если бы вы использовали стрелочную функцию.

// Плохо: обработчик "зашит" на одну конкретную переменную.
onCompleteHandler() {
    image.setScale(2); // А если image недоступен здесь?
}

// Хорошо: обработчик получает объект для работы как параметр.
onCompleteHandler(tween, targets, targetImage) {
    targetImage.setScale(2); // Работает для любого переданного спрайта.
}

Практические идеи для использования

Колбэк onComplete открывает множество возможностей для геймдизайна:

*   **Цепочка анимаций**: В колбэке первого твина запускайте второй, создавая сложные последовательности.
*   **Управление состоянием**: Помечайте объект как "достигший цели", что может запустить проверку условий победы.
*   **Визуальные и звуковые эффекты**: Воспроизведите частицы взрыва (`this.add.particles`) или звук (`this.sound.play`) при завершении движения.
*   **Активация физики**: После плавного появления "включите" физику для объекта с помощью `this.physics.add.existing(image)`.
onCompleteHandler(tween, targets, targetImage) {
    // Запуск звукового эффекта
    this.sound.play('pickup');
    // Создание частиц в позиции объекта
    this.add.particles(targetImage.x, targetImage.y, 'particleTexture', { /* конфиг */ });
    // Уничтожение объекта после анимации
    targetImage.destroy();
}

*Примечание: чтобы использовать this.sound или this.add внутри обработчика, убедитесь, что контекст this привязан правильно. В примере это работает, потому что обработчик — метод сцены, а в колбэк передается тот же this.*

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

Колбэк onComplete — это мощный и простой инструмент для синхронизации игровой логики с анимацией. Он превращает линейное движение в событие, которое может запускать любые последующие действия в игре. Для экспериментов попробуйте создать каскад твинов, где завершение одного запускает следующий, или свяжите колбэк с системой событий (this.events) сцены для более сложной архитектуры.