О чем этот пример
При создании реалистичного движения в играх важно не только разогнать объект, но и правильно его остановить. Сила сопротивления (drag) в Phaser отвечает за постепенное замедление тела, создавая эффект инерции или трения. В этой статье мы разберем, как работает сопротивление на примере 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');
}
create ()
{
this.physics.add.image(100, 100, 'block').setVelocityX(100).setDragX(10);
this.physics.add.image(100, 200, 'block').setVelocityX(100).setDragX(20);
this.physics.add.image(100, 300, 'block').setVelocityX(100).setDragX(50);
this.physics.add.image(100, 400, 'block').setVelocityX(100).setDragX(100);
this.physics.add.image(100, 500, 'block').setVelocityX(100).setDragX(1000);
const bodies = Array.from(this.physics.world.bodies);
for (const body of bodies)
{
const { drag, velocity } = body;
console.log('Body will stop after %.3f seconds', velocity.x / drag.x);
}
}
update ()
{
const bodies = Array.from(this.physics.world.bodies);
for (const body of bodies)
{
body.debugBodyColor = body.speed > 0 ? 0x00ff00 : 0xff0000;
}
}
}
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);
Что такое сопротивление (Drag) в Arcade Physics?
В Arcade Physics сопротивление (drag) — это постоянная сила, которая действует противоположно направлению движения тела, постепенно уменьшая его скорость. Это не трение о поверхность, а скорее линейное сопротивление среды (например, воздуха или воды).
Ключевая особенность: сила сопротивления не зависит от скорости тела. Она постоянна. Это значит, что тело будет замедляться линейно, пока его скорость не достигнет нуля. Методы setDragX(drag) и setDragY(drag) устанавливают значение этого сопротивления по соответствующим осям. Чем больше значение, тем быстрее объект остановится.
Настройка сцены и создание физических тел
В примере создается одна сцена, которая загружает спрайт и в методе create() создает пять идентичных блоков с разным сопротивлением. Конфигурация игры включает Arcade Physics с включенным режимом отладки (debug: true), что позволяет видеть хитбоксы тел.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: { debug: true }
},
scene: Example
};
В методе create() создаются пять физических тел — спрайты блока. Каждому задается одинаковая начальная скорость по оси X (100 пикселей в секунду), но разное сопротивление (drag.x).
create ()
{
this.physics.add.image(100, 100, 'block').setVelocityX(100).setDragX(10);
this.physics.add.image(100, 200, 'block').setVelocityX(100).setDragX(20);
this.physics.add.image(100, 300, 'block').setVelocityX(100).setDragX(50);
this.physics.add.image(100, 400, 'block').setVelocityX(100).setDragX(100);
this.physics.add.image(100, 500, 'block').setVelocityX(100).setDragX(1000);
}
Расчет времени до полной остановки
Поскольку сопротивление постоянно, а начальная скорость известна, можно легко вычислить время, через которое тело остановится. Формула проста: время = скорость / сопротивление. В коде примера это демонстрируется путем перебора всех тел в физическом мире и вывода результата в консоль.
const bodies = Array.from(this.physics.world.bodies);
for (const body of bodies)
{
const { drag, velocity } = body;
console.log('Body will stop after %.3f seconds', velocity.x / drag.x);
}
Для первого тела (скорость 100, сопротивление 10) расчет будет: 100 / 10 = 10 секунд. Для последнего (сопротивление 1000) — всего 0.1 секунды. Этот расчет работает, потому что в Arcade Physics скорость уменьшается на значение сопротивления каждую секунду.
Визуализация состояния в реальном времени
Метод update() вызывается на каждом кадре и используется для визуальной обратной связи. В данном примере он меняет цвет отладочной обводки тела в зависимости от того, движется ли оно.
Свойство body.speed хранит текущую общую скорость тела (скаляр). Если скорость больше нуля, цвет устанавливается зеленым (0x00ff00), если тело остановилось — красным (0xff0000). Свойство debugBodyColor управляет цветом отладочной отрисовки для Arcade Physics.
update ()
{
const bodies = Array.from(this.physics.world.bodies);
for (const body of bodies)
{
body.debugBodyColor = body.speed > 0 ? 0x00ff00 : 0xff0000;
}
}
Запустив пример, вы увидите, как блоки с меньшим сопротивлением (верхние) будут дольше оставаться зелеными и проедут дальше, в то время как нижний блок почти мгновенно станет красным.
Практическое применение и настройки
Сопротивление — отличный инструмент для моделирования различных материалов и сред. * **Низкие значения (1-50):** Подходят для имитации движения по льду, в воздухе или для очень массивных объектов с большой инерцией. * **Высокие значения (100-500):** Используются для быстрой остановки, создания эффекта "трения" о землю или движения в густой среде (например, под водой). * **Очень высокие значения (1000+):** Фактически мгновенная остановка, может использоваться для резкого прекращения движения по команде.
Важно помнить, что сопротивление применяется отдельно по осям. Объект, движущийся по диагонали, будет замедляться с разной скоростью по осям X и Y, если заданы разные drag.x и drag.y. Для равномерного замедления устанавливайте одинаковые значения.
Что попробовать дальше
Сопротивление (drag) в Phaser — это простой, но мощный механизм для управления замедлением объектов. Используя линейную модель, он позволяет легко предсказывать поведение тел и настраивать ощущения от игры. Для экспериментов попробуйте
- Применить
setDragY()для падающих объектов, чтобы создать эффект парашюта или вязкой жидкости - Динамически менять сопротивление в
update()в зависимости от поверхности, по которой движется персонаж - Скомбинировать сопротивление с ускорением (
setAcceleration) для создания сложных кривых движения
