О чем этот пример
В аркадных играх часто нужно ограничивать скорость объектов, чтобы управление оставалось отзывчивым, а геймплей — комфортным. Phaser Arcade Physics предоставляет для этого простой и эффективный метод `setMaxSpeed()`. В этой статье мы разберем, как задать предел скорости для спрайта, визуализировать его и реализовать инерционное управление кораблем, подобное классическим играм про космос.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
text;
cursors;
circle;
sprite;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ship', 'assets/games/asteroids/ship.png');
}
create ()
{
this.sprite = this.physics.add.image(400, 300, 'ship');
this.sprite.body.setMaxSpeed(200);
this.circle = this.add.circle(this.sprite.x, this.sprite.y, 0.5 * this.sprite.body.maxSpeed, 0xffffff, 0.2);
console.log(this.circle);
this.cursors = this.input.keyboard.createCursorKeys();
this.text = this.add.text(10, 10, '', { font: '16px Courier', fill: '#00ff00' });
}
update ()
{
if (this.cursors.up.isDown)
{
this.physics.velocityFromRotation(this.sprite.rotation, this.sprite.body.maxSpeed, this.sprite.body.acceleration);
}
else
{
this.sprite.setAcceleration(0);
}
if (this.cursors.left.isDown)
{
this.sprite.setAngularVelocity(-300);
}
else if (this.cursors.right.isDown)
{
this.sprite.setAngularVelocity(300);
}
else
{
this.sprite.setAngularVelocity(0);
}
this.text.setText(`Speed: ${this.sprite.body.speed}`);
this.physics.world.wrap(this.sprite, 100);
this.circle.setPosition(this.sprite.x, this.sprite.y);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
scene: Example
};
const game = new Phaser.Game(config);
Инициализация сцены и физического тела
В методе create() создается физический спрайт корабля. Ключевой момент — сразу после создания тела спрайта устанавливается его максимальная скорость. Это глобальное ограничение, которое будет применяться ко всем последующим расчётам движения.
Также создается полупрозрачный круг, радиус которого равен половине максимальной скорости. Этот круг будет визуальным индикатором зоны достижимой скорости.
this.sprite = this.physics.add.image(400, 300, 'ship');
this.sprite.body.setMaxSpeed(200);
this.circle = this.add.circle(this.sprite.x, this.sprite.y, 0.5 * this.sprite.body.maxSpeed, 0xffffff, 0.2);
Управление ускорением и поворотом
Логика управления вынесена в метод update(). При нажатии стрелки вверх (cursors.up) происходит расчёт вектора ускорения. Функция physics.velocityFromRotation() преобразует текущий угол поворота спрайта (this.sprite.rotation) в вектор ускорения, используя максимальную скорость как величину этого вектора. Это создает эффект инерционного разгона в направлении носа корабля.
Стрелки влево и вправо управляют угловой скоростью (setAngularVelocity), позволяя вращать корабль. Когда клавиши отпущены, ускорение и вращение сбрасываются в ноль.
if (this.cursors.up.isDown)
{
this.physics.velocityFromRotation(this.sprite.rotation, this.sprite.body.maxSpeed, this.sprite.body.acceleration);
}
else
{
this.sprite.setAcceleration(0);
}
if (this.cursors.left.isDown)
{
this.sprite.setAngularVelocity(-300);
}
else if (this.cursors.right.isDown)
{
this.sprite.setAngularVelocity(300);
}
else
{
this.sprite.setAngularVelocity(0);
}
Визуализация и отладка
Для удобства отладки в игре реализовано несколько визуальных элементов. Текст в левом верхнем углу в реальном времени отображает текущую фактическую скорость спрайта, которую можно получить из this.sprite.body.speed.
Круг-индикатор следует за кораблем, наглядно показывая область, которую объект может достигнуть за один кадр при максимальной скорости. Метод physics.world.wrap() обеспечивает телепортацию спрайта на противоположную сторону холста, если он выходит за его границы, с заданным отступом в 100 пикселей.
this.text.setText(`Speed: ${this.sprite.body.speed}`);
this.physics.world.wrap(this.sprite, 100);
this.circle.setPosition(this.sprite.x, this.sprite.y);
Что попробовать дальше
Использование setMaxSpeed() — это простой способ контролировать движение и балансировать геймплей. Для экспериментов попробуйте изменить значение максимальной скорости в рантайме в зависимости от состояния игры (например, при активации 'ускорения'), привязать радиус индикатора к текущей скорости или использовать другой метод ограничения — setDrag() — для создания эффекта вязкой среды.
