О чем этот пример

В Arcade Physics Phaser есть простое, но мощное свойство `angularVelocity`, которое управляет скоростью вращения тела. Этот пример показывает, как создать реалистичное управление самолётом, где поворот влияет на направление движения. Вы научитесь связывать вращение спрайта с его вектором скорости, создавая классическую механику полёта, и использовать полезный метод `wrap` для бесшовного перемещения объекта по краям игрового мира.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    plane;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('clouds', 'assets/skies/clouds.png');
        this.load.image('plane', 'assets/sprites/ww2plane90.png');
    }

    create ()
    {
        this.add.image(0, 0, 'clouds').setOrigin(0, 0);

        this.plane = this.physics.add.image(400, 300, 'plane')
            .setCircle(24, 0, 7.5)
            .setVelocity(0, -100);

        this.input.keyboard
            .on('keydown-LEFT', () => { this.plane.setAngularVelocity(-60); })
            .on('keydown-RIGHT', () => { this.plane.setAngularVelocity(60); })
            .on('keydown-UP', () => { this.plane.setAngularVelocity(0); });
    }

    update ()
    {
        this.physics.velocityFromAngle(this.plane.angle, 150, this.plane.body.velocity);

        this.physics.world.wrap(this.plane, 32);
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: { debug: false }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка сцены и загрузка ассетов

Класс Example расширяет Phaser.Scene. В методе preload задаётся базовый URL для загрузки и загружаются два изображения: фон с облаками и спрайт самолёта.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('clouds', 'assets/skies/clouds.png');
this.load.image('plane', 'assets/sprites/ww2plane90.png');

Создание физического тела и настройка управления

В методе create сначала добавляется фоновое изображение. Затем создаётся физическое тело самолёта с помощью this.physics.add.image. Ключевые моменты: - Метод .setCircle(24, 0, 7.5) задаёт круглую коллизию для спрайта самолёта (радиус 24 пикселя со смещением). Это важно для корректного взаимодействия с физикой. - .setVelocity(0, -100) задаёт начальную скорость движения вверх.

Управление привязывается к клавиатуре: клавиши LEFT/RIGHT изменяют угловую скорость (angularVelocity), заставляя самолёт вращаться, а клавиша UP сбрасывает её до нуля.

this.plane = this.physics.add.image(400, 300, 'plane')
    .setCircle(24, 0, 7.5)
    .setVelocity(0, -100);

this.input.keyboard
    .on('keydown-LEFT', () => { this.plane.setAngularVelocity(-60); })
    .on('keydown-RIGHT', () => { this.plane.setAngularVelocity(60); })
    .on('keydown-UP', () => { this.plane.setAngularVelocity(0); });

Связь угла поворота и вектора скорости

Сердце механики полёта находится в методе `update`. Чтобы самолёт летел в ту сторону, куда смотрит его нос, используется метод `this.physics.velocityFromAngle`.
- Первый аргумент — текущий угол поворота спрайта (`this.plane.angle`).
- Второй аргумент — величина скорости (150).
- Третий аргумент — целевой объект вектора скорости (`this.plane.body.velocity`).

Этот метод каждый кадр пересчитывает вектор скорости (velocity.x и velocity.y) на основе угла, создавая ощущение реалистичного полёта.

this.physics.velocityFromAngle(this.plane.angle, 150, this.plane.body.velocity);

Бесшовный переход через границы мира

Чтобы самолёт не улетал за границы экрана, используется метод `this.physics.world.wrap`.
- Первый аргумент — объект для обёртки (`this.plane`).
- Второй аргумент — отступ (padding) в пикселях (32). Это означает, что объект начнёт переходить на противоположную сторону, когда его центр отдалится от края мира на 32 пикселя.

Этот подход удобнее, чем ручная проверка координат, и создаёт плавный, непрерывный игровой мир.

this.physics.world.wrap(this.plane, 32);

Конфигурация игры и запуск

В конце файла определяется объект конфигурации игры config и создаётся её экземпляр. Важно настроить физическую систему arcade.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: { debug: false }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Что попробовать дальше

Пример демонстрирует элегантную связку angularVelocity и velocityFromAngle для создания интуитивного управления летательным аппаратом. Для экспериментов попробуйте изменить скорость вращения или величину скорости полёта, добавьте ускорение/торможение по клавише DOWN или реализуйте стрельбу в направлении движения самолёта, используя его текущий угол.