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

В играх часто требуется анимировать объекты, которые при этом должны сохранять физические свойства и корректно сталкиваться с другими телами. Прямая анимация спрайта через `tweens` или `timeline` не обновляет физическое тело, что приводит к прохождению объектов друг сквозь друга. В этой статье разберем, как правильно анимировать физическое тело с помощью твинов в Arcade Physics, чтобы коллизии обрабатывались корректно. Этот подход полезен для создания движущихся платформ, врагов, патрулирующих территорию, или любых интерактивных анимированных препятствий.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('block', 'assets/sprites/block.png');
        this.load.image('dude', 'assets/sprites/phaser-dude.png');
    }

    create ()
    {
        // this.physics.world.OVERLAP_BIAS = 8;

        const block = this.physics.add.image(400, 200, 'block');

        block.body.allowGravity = false;
        block.body.immovable = true;
        block.body.moves = false;

        const sprite = this.physics.add.image(400, 100, 'dude');

        this.tweens.add({
            targets: block,
            y: 400,
            duration: 2000,
            ease: 'Sine.easeInOut',
            repeat: -1,
            yoyo: true
        });

        this.physics.add.collider(sprite, block);
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: {
            debug: true,
            gravity: { y: 300 },
            overlapBias: 8
        }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Проблема: анимация спрайта vs анимация тела

По умолчанию, когда вы применяете твин к игровому объекту (Game Object), он изменяет его свойства, такие как `x,y,scale. Однако, если этот объект также является физическим телом (например, создан черезthis.physics.add.image), система физики Arcade вычисляет положение и коллизии, основываясь на отдельном свойствеbody`. При стандартной анимации спрайта, физическое тело может "отставать" или вообще не обновлять свою позицию, что приводит к некорректным столкновениям.

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

Решение: твин тела и настройка overlapBias

В предоставленном примере реализовано корректное решение. Давайте разберем его по шагам.

Сначала создается статичный блок и управляемый спрайт. Обратите внимание на настройки тела блока:

const block = this.physics.add.image(400, 200, 'block');
block.body.allowGravity = false;
block.body.immovable = true;
block.body.moves = false;

Здесь immovable: true указывает, что при столкновении этот объект не будет отталкиваться (как массивная платформа). moves: false отключает расчет движения силами физики для этого тела, что важно, так как его движением будет управлять твин.

Затем к объекту block применяется твин, который анимирует его свойство `y`:

this.tweens.add({
    targets: block,
    y: 400,
    duration: 2000,
    ease: 'Sine.easeInOut',
    repeat: -1,
    yoyo: true
});

Phaser 3 автоматически синхронизирует позицию спрайта и его Arcade Physics тело, когда тело имеет флаг moves = false. Это означает, что твин, изменяя block.y, также обновит block.body.y, и коллайдер будет двигаться вместе с визуальным представлением.

Наконец, создается коллайдер между спрайтом и блоком:

this.physics.add.collider(sprite, block);

Особое внимание стоит обратить на настройку overlapBias в конфигурации физики. В коде примера она задана равной 8. Эта настройка помогает системе более агрессивно корректировать позиции объектов при обработке перекрытия (overlap), что особенно важно для быстро движущихся тел.

physics: {
    default: 'arcade',
    arcade: {
        debug: true,
        gravity: { y: 300 },
        overlapBias: 8 // Важная настройка для движущихся тел
    }
}

Важные свойства физического тела для анимации

Для успешного совмещения твинов и физики необходимо правильно настроить тело.

* **body.moves**: Установка в false — это ключ. Тело не будет управляться скоростью или ускорением движка физики. Вместо этого его позиция может быть установлена напрямую (в нашем случае — твином), и система коллизий будет учитывать это новое положение. * **body.immovable**: Если ваш анимированный объект должен оставаться на месте при столкновении (например, движущаяся платформа), установите это свойство в true. В противном случае при столкновении оба тела будут рассчитывать отскок, что может привести к неожиданному поведению. * **body.allowGravity**: Обычно для анимированных платформ гравитацию отключают.

Эти три свойства часто идут вместе в подобных сценариях.

// Типичная конфигурация тела для анимированной платформы
platform.body.allowGravity = false;
platform.body.immovable = true;
platform.body.moves = false;

Альтернативный подход: твин свойства body.y

Хотя в данном примере твин применяется к самому игровому объекту, вы также можете анимировать свойства его тела напрямую. Это может быть полезно для более явного контроля.

this.tweens.add({
    targets: block.body,
    y: 400,
    duration: 2000,
    ease: 'Sine.easeInOut',
    repeat: -1,
    yoyo: true
});

Однако при таком подходе визуальная позиция спрайта (block.y) не будет обновляться автоматически. Вам потребуется синхронизировать ее вручную, например, в методе update() сцены:

update() {
    block.y = block.body.y;
}

Поэтому первый подход (твин объекта с moves: false) является более предпочтительным и идиоматичным для Phaser 3, так как движок берет синхронизацию на себя.

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

Анимация физических тел через твины в Phaser — мощный прием для создания динамичной игровой среды. Ключевые шаги: создать тело с moves: false, применить твин к игровому объекту и настроить overlapBias для более точных коллизий. Для экспериментов попробуйте: создать сложный маршрут движения через timeline, анимировать группу тел одновременно, изменить overlapBias на лету и посмотреть на разницу в поведении столкновений или использовать этот метод для создания движущихся врагов, которые отталкивают игрока.