О чем этот пример
Анимации (tweens) в Phaser — мощный инструмент для плавного перемещения объектов. Но что, если цель анимации должна меняться прямо во время её выполнения? Например, объект должен преследовать курсор мыши, который постоянно двигается. Классический tween со статичными координатами здесь не подойдёт. В этой статье разберем продвинутую технику: использование функций в качестве значений свойств (`props`) для tween. Это позволяет вычислять конечную точку анимации в реальном времени на каждом кадре, создавая динамичные и интерактивные эффекты, которые реагируют на действия игрока.
Версия 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('ball', 'assets/sprites/shinyball.png');
this.load.image('cursor', 'assets/sprites/drawcursor.png');
}
create ()
{
var from = this.add.image(400, 300, 'ball').setAlpha(0.6);
var marker = this.add.image(400, 300, 'cursor').setAlpha(0.6);
var image = this.add.image(400, 300, 'ball');
this.input.on('pointerdown', function (pointer)
{
marker.setPosition(pointer.x, pointer.y);
});
var tween = this.tweens.add({
targets: image,
props: {
x: { value: function () { return marker.x; }, ease: 'Power1' },
y: { value: function () { return marker.y; }, ease: 'Power3' }
},
duration: 500,
yoyo: true,
repeat: -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 плавно меняет свойство объекта (например, координату `x) от начального значения к заранее заданному конечному. В нашем примере конечная точка (xиy) не является фиксированным числом. Вместо этого, в конфигурации tween указаны функции, которые возвращают текущие координаты объекта-маркера (marker`). Эти функции вызываются многократно в процессе анимации, обеспечивая динамическое обновление цели.
Разбор кода: от загрузки до создания tween
Давайте пройдемся по ключевым частям примера.
В методе preload загружаются два спрайта: шар (ball) и курсор (cursor).
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball', 'assets/sprites/shinyball.png');
this.load.image('cursor', 'assets/sprites/drawcursor.png');
}
В методе create создаются три основных объекта:
- from и image — два одинаковых шара.
- marker — спрайт курсора, который будет задавать цель.
create ()
{
var from = this.add.image(400, 300, 'ball').setAlpha(0.6);
var marker = this.add.image(400, 300, 'cursor').setAlpha(0.6);
var image = this.add.image(400, 300, 'ball');
}
Затем на событие клика мыши (pointerdown) вешается обработчик, который перемещает маркер в точку клика.
this.input.on('pointerdown', function (pointer)
{
marker.setPosition(pointer.x, pointer.y);
});
Сердце примера: конфигурация динамического tween
Самое важное — создание tween с помощью this.tweens.add. Обратите внимание на структуру свойства props.
var tween = this.tweens.add({
targets: image,
props: {
x: { value: function () { return marker.x; }, ease: 'Power1' },
y: { value: function () { return marker.y; }, ease: 'Power3' }
},
duration: 500,
yoyo: true,
repeat: -1
});
Ключевые моменты:
1. **targets: image**: Анимируемым объектом является наш основной шар (image).
2. **props.x.value и props.y.value**: Вместо чисел здесь передаются **функции**. Каждый раз, когда tween обновляет позицию объекта, он вызывает эти функции, чтобы получить актуальные координаты marker. Это позволяет цели анимации "двигаться" во время её выполнения.
3. **ease**: Задает функцию easing (плавности). Для `xиспользуется'Power1', дляy—'Power3'`, что создает интересный волнообразный эффект движения по разным осям.
4. **yoyo: true**: После достижения (вычисленной) цели анимация проигрывается в обратном порядке, возвращая объект к начальной точке.
5. **repeat: -1**: Анимация повторяется бесконечно.
Как это работает в реальном времени
1. Tween стартует, пытаясь изменить image.x от текущего значения до результата вызова function () { return marker.x; }.
2. Каждый кадр tween пересчитывает прогресс анимации и вычисляет промежуточное значение для `xиy`.
3. **Важно:** Функции для value вызываются многократно в процессе анимации, а не один раз в начале. Поэтому, если вы переместите marker кликом мыши, tween тут же начнет учитывать его новую позицию как конечную цель. Это создает эффект плавного преследования шаром движущегося маркера.
4. Из-за параметров yoyo и repeat шар постоянно курсирует между своей стартовой позицией и текущим положением маркера.
Что попробовать дальше
Использование функций в свойстве value — это мощный прием для создания сложных, реактивных анимаций в Phaser. Вы вышли за рамки простых перемещений из точки A в точку B.
**Идеи для экспериментов:**
- Заставьте объект следовать не за маркером, а за другим движущимся спрайту (например, за игроком).
- Внутри функции можно добавить сложную логику: вычисление точки по формуле, случайное смещение, или условие, меняющее цель.
- Попробуйте применить эту технику к другим свойствам, например, к scale или angle, чтобы создать динамическое вращение или пульсацию объекта, зависящую от расстояния до цели.
