О чем этот пример
В Phaser 3 физика и анимация тесно связаны. Обычно твины управляют позицией или свойствами спрайтов, но что если нужно плавно менять не позицию, а скорость физического тела? Этот пример показывает, как использовать систему твинов Phaser для анимации вектора скорости (`body.velocity`) физического тела, создавая сложные траектории движения, которые корректно взаимодействуют с другими объектами через физический движок. Этот подход полезен для создания подвижных платформ, вражеских патрулей или любых объектов, чье движение должно быть плавным, но при этом сталкиваться с игровым миром.
Версия 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');
this.load.image('ball', 'assets/sprites/blue_ball.png');
this.load.image('sky', 'assets/skies/cavern2.png');
}
create ()
{
this.add.image(400, 300, 'sky');
const block = this.physics.add.image(100, 500, 'block');
block.body.immovable = true;
block.body.allowGravity = false;
const dude = this.physics.add.image(100, 0, 'dude');
const balls = this.physics.add.group({
key: 'ball',
frameQuantity: 192,
gridAlign: { width: 16, height: 12, cellWidth: 50, cellHeight: 50, position: Phaser.Display.Align.CENTER },
allowGravity: false
});
this.tweens.chain({
targets: block.body.velocity,
loop: -1,
tweens: [
{ x: 0, y: -200, duration: 2000, ease: 'Stepped' },
{ x: 0, y: 0, duration: 1000, ease: 'Stepped' },
{ x: 150, y: 100, duration: 4000, ease: 'Stepped' },
{ x: 0, y: -200, duration: 2000, ease: 'Stepped' },
{ x: 0, y: 0, duration: 1000, ease: 'Stepped' },
{ x: -150, y: 100, duration: 4000, ease: 'Stepped' }
]
});
this.physics.add.collider(block, dude);
this.physics.add.collider(block, balls);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
debug: false,
gravity: { y: 600 }
}
},
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и настройка физики
В методе preload загружаются необходимые изображения: фон, блок, персонаж и шарики. Ключевой шаг происходит в конфигурации игры при создании экземпляра Phaser.Game. Здесь активируется физический движок Arcade с сильной гравитацией, направленной вниз.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
debug: false,
gravity: { y: 600 }
}
},
scene: Example
};
Высокое значение gravity.y: 600 заставляет все физические тела с ускорением падать вниз. Однако в коде для некоторых объектов гравитация будет отключена, что позволяет контролировать их движение вручную.
Создание и настройка физических тел
В методе create сначала добавляется фоновое изображение. Затем создаются три типа физических объектов.
1. **Неподвижный блок (block)**: Это главный объект, скорость которого мы будем анимировать. Он создается с помощью this.physics.add.image. Его тело делается неподвижным (immovable = true), что означает, что при столкновении он не будет сдвигаться другими объектами. Гравитация для него отключается (allowGravity = false).
const block = this.physics.add.image(100, 500, 'block');
block.body.immovable = true;
block.body.allowGravity = false;
2. **Персонаж (dude)**: Создается как обычное физическое изображение. На него действует гравитация, объявленная в конфиге, поэтому он начнет падать сверху.
3. **Группа шариков (balls)**: Создается 192 шара, выровненных по сетке. Для каждого члена группы также отключается гравитация. Это статичные объекты, которые будут служить препятствиями.
const balls = this.physics.add.group({
key: 'ball',
frameQuantity: 192,
gridAlign: { width: 16, height: 12, cellWidth: 50, cellHeight: 50, position: Phaser.Display.Align.CENTER },
allowGravity: false
});
Цепочка твинов для анимации скорости
Сердце примера — применение твина не к позиции спрайта, а к вектору скорости его физического тела (block.body.velocity). Твин будет плавно интерполировать значения velocity.x и velocity.y между ключевыми кадрами.
Используется this.tweens.chain(), который позволяет создать последовательность (chain) из нескольких твинов, выполняющихся один за другим. Цикл бесконечный (loop: -1).
this.tweens.chain({
targets: block.body.velocity,
loop: -1,
tweens: [
{ x: 0, y: -200, duration: 2000, ease: 'Stepped' },
{ x: 0, y: 0, duration: 1000, ease: 'Stepped' },
{ x: 150, y: 100, duration: 4000, ease: 'Stepped' },
{ x: 0, y: -200, duration: 2000, ease: 'Stepped' },
{ x: 0, y: 0, duration: 1000, ease: 'Stepped' },
{ x: -150, y: 100, duration: 4000, ease: 'Stepped' }
]
});
Каждый твин в массиве определяет целевые значения скорости по осям X и Y и время перехода. Например, первый твин за 2 секунды меняет вертикальную скорость с текущей до -200 (движение вверх). Важно отметить использование линейной интерполяции ease: 'Stepped'. Это значит, что скорость меняется резко, без плавного разгона и торможения, создавая роботизированное, механическое движение.
Организация столкновений
Чтобы анимированный блок взаимодействовал с миром, необходимо добавить коллайдеры. Phaser Arcade Physics автоматически рассчитает столкновения между телами, если их скорости или позиции изменятся.
this.physics.add.collider(block, dude);
this.physics.add.collider(block, balls);
Первый коллайдер обеспечивает взаимодействие между блоком и падающим персонажем. Когда блок движется, он будет сталкиваться с dude, отталкивая его согласно законам физики.
Второй коллайдер регистрирует столкновения между блоком и каждым шариком из группы. Так как блок immovable, при столкновении он останется на месте (точнее, продолжит движение по заданной твином траектории), а шарики будут отлетать от него. Визуально это создает эффект "бульдозера", разгребающего поле из шаров.
Что попробовать дальше
Анимация скорости через твины — мощный прием для создания нестандартного движения, которое полностью интегрировано в физическую модель игры. Вы можете экспериментировать: замените ease: 'Stepped' на 'Power2' или 'Bounce', чтобы получить плавное ускорение и замедление. Попробуйте сделать блок подвижным (immovable: false) и посмотрите, как он будет взаимодействовать с персонажем. Или привяжите твин к скорости персонажа, чтобы создавать спецэффекты, например, скольжение по льду или порывы ветра.
