О чем этот пример
В Arcade Physics Phaser'а по умолчанию вращение спрайта (`setAngularVelocity`) никак не связано с его линейной скоростью. Это выглядит неестественно, когда объект, например, мяч, движется, но не вращается. В примере из официальной коллекции показан элегантный способ синхронизировать угловую скорость спрайта с его перемещением по поверхности, создавая убедительный эффект качения. Этот приём оживит ваши платформеры, пинболы или любые игры, где важна визуальная связь движения и вращения.
Версия 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('ball', 'assets/sprites/wizball.png');
}
create ()
{
const wheel = this.physics.add.image(50, 300, 'ball')
.setAccelerationX(100)
.setBounce(1)
.setCollideWorldBounds(true);
this.physics.world.on('worldstep', () =>
{
wheel.setAngularVelocity(
Phaser.Math.RadToDeg(wheel.body.velocity.x / wheel.body.halfWidth)
);
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: { debug: true }
},
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
Как и в любом проекте Phaser, начинаем с базовой настройки сцены. В методе preload указываем базовый URL для загрузки ресурсов и загружаем одно изображение — спрайт мяча.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball', 'assets/sprites/wizball.png');
}
Создание физического тела и настройка его поведения
В методе create мы создаём физический спрайт — наш "мяч". Ключевой момент: мы сразу настраиваем его физические свойства, используя методы цепочки (chaining).
- setAccelerationX(100) — задаёт постоянное ускорение по оси X, заставляя мяч разгоняться вправо.
- setBounce(1) — устанавливает коэффициент упругости (реституции) в 1. Это означает идеально упругий отскок без потерь энергии при столкновении.
- setCollideWorldBounds(true) — включает столкновение тела с границами мира (краями игрового поля). В комбинации с setBounce(1) это заставляет мяч отскакивать от стен.
const wheel = this.physics.add.image(50, 300, 'ball')
.setAccelerationX(100)
.setBounce(1)
.setCollideWorldBounds(true);
Магия синхронизации: событие `worldstep`
Сердце примера — обработка события worldstep, которое генерируется физическим движком Arcade на каждом шаге симуляции. Именно здесь происходит расчёт и синхронизация угловой скорости.
Внутри обработчика события мы берём текущую линейную скорость тела по оси X (wheel.body.velocity.x) и делим её на радиус спрайта. Поскольку в Arcade Physics тело спрайта является AABB (axis-aligned bounding box), его "радиус" для расчётов — это половина ширины (body.halfWidth).
Полученное значение (скорость в пикселях в секунду, делённая на радиус в пикселях) даёт нам угловую скорость в радианах в секунду. Метод Phaser.Math.RadToDeg конвертирует её в градусы в секунду, что является требуемым форматом для метода setAngularVelocity.
Таким образом, угловая скорость автоматически подстраивается под линейную на каждом кадре физики.
this.physics.world.on('worldstep', () =>
{
wheel.setAngularVelocity(
Phaser.Math.RadToDeg(wheel.body.velocity.x / wheel.body.halfWidth)
);
});
Конфигурация игры и запуск
Для работы примера необходима стандартная конфигурация игры с включённым физическим движком Arcade. Обратите внимание на параметр debug: true — он отрисует контуры физических тел, что полезно для визуализации и отладки.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: { debug: true }
},
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Используя событие worldstep для связи линейной и угловой скорости, вы можете легко создавать правдоподобно катящиеся объекты в своих играх. Для экспериментов попробуйте изменить ускорение, добавить трение (setDrag), применить формулу к оси Y для моделирования спуска с горки или привязать расчёт к спрайтам разного размера. Этот подход открывает путь к более сложной и приятной глазу физике взаимодействий.
