О чем этот пример
Встроенные функции плавности, такие как 'sine.in' или 'quad.out', покрывают большинство стандартных сценариев анимации. Однако для создания по-настоящему уникального движения спрайтов, которое подчеркнёт стиль вашей игры, необходимы собственные решения. В этом примере показано, как определить кастомную функцию плавности (ease) прямо внутри твина, используя математические выражения JavaScript. Этот приём даёт полный контроль над кривой анимации, позволяя создавать эффекты отскока, упругости или любые другие нелинейные переходы, которые сложно реализовать стандартными средствами.
Версия 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,
duration: 3000,
ease: function (t)
{
return Math.pow(Math.sin(t * 3), 3);
},
delay: 1000
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
var game = new Phaser.Game(config);
Загрузка ресурсов и подготовка сцены
В методе preload() мы загружаем спрайт, который будем анимировать. Базовая часть пути задаётся через setBaseURL, что удобно для загрузки ресурсов из удалённого репозитория.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
В методе create() создаются два изображения с одним и тем же спрайтом 'block'. Первое изображение (marker) служит неподвижным маркером, обозначающим стартовую позицию. Его прозрачность уменьшена через setAlpha(0.3). Второе изображение (image) — это непосредственно объект анимации.
Настройка твина с пользовательской функцией ease
Анимация создаётся с помощью this.tweens.add(). Конфигурационный объект твина содержит стандартные свойства:
- targets: объект для анимации (наш image).
- `x`: конечная координата по оси X.
- duration: длительность анимации в миллисекундах.
- delay: задержка перед началом анимации.
Ключевой момент — свойство ease. Вместо строки с именем встроенной функции, здесь передаётся пользовательская JavaScript-функция.
this.tweens.add({
targets: image,
x: 600,
duration: 3000,
ease: function (t)
{
return Math.pow(Math.sin(t * 3), 3);
},
delay: 1000
});
Функция ease получает один аргумент `t` — нормализованное время анимации, значение от 0 (начало) до 1 (конец). Задача функции — преобразовать это линейное время в нелинейный прогресс анимации, возвращая соответствующее значение (также обычно от 0 до 1).
Как работает пользовательская функция плавности
Рассмотрим математику из примера: Math.pow(Math.sin(t * 3), 3).
1. t * 3: Умножаем нормализованное время на 3. Это означает, что за время анимации синусоида совершит 1.5 полных колебаний (поскольку sin(3 * 1) = sin(3) ≈ 0.141).
2. Math.sin(...): Берём синус от полученного значения. Синус даёт волнообразное изменение между -1 и 1.
3. Math.pow(..., 3): Возводим результат синуса в третью степень. Это усиливает эффект волны и сохраняет знак (отрицательные значения остаются отрицательными).
Итоговая кривая создаёт эффект нескольких "отскоков" или осцилляций спрайта по пути к конечной точке. Движение начинается с ускорения, затем происходит несколько волнообразных замедлений и ускорений, прежде чем спрайт окончательно остановится.
Важно помнить: функция ease вызывается множество раз за время анимации, и её результат определяет текущую позицию image.x между начальным (100) и конечным (600) значением по формуле: start + (end - start) * easeValue.
Конфигурация игры и запуск
Сцена добавляется в конфигурацию игры. Обратите внимание на параметр backgroundColor, который задаёт тёмно-серый фон, контрастирующий со спрайтом.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
var game = new Phaser.Game(config);
После создания экземпляра Phaser.Game с этой конфигурацией автоматически вызываются методы preload, create, а затем начинается игровой цикл.
Что попробовать дальше
Использование кастомных функций ease открывает безграничные возможности для тонкой настройки анимации в Phaser. Вы можете экспериментировать с другими математическими функциями: попробуйте Math.abs(Math.sin(t * 5)) для создания эффекта пульсации, или комбинацию степенных функций для резких ускорений и плавных замедлений. Для сложных кривых можно заранее определить массив точек и использовать интерполяцию внутри функции ease. Это мощный инструмент, который делает движение игровых объектов не просто функциональным, но и стилистически выразительным.
