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

Правильное управление вращением — основа динамичной игровой графики. В Phaser для этого есть два ключевых свойства: `angle` в градусах и `rotation` в радианах. Эта статья наглядно покажет, как они связаны и как использовать их для плавной анимации вращения ваших игровых объектов. Вы научитесь переключаться между градусами и радианами, что пригодится при работе с физикой, анимацией и математикой игрового мира.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    arrow;
    text;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('arrow', 'assets/sprites/longarrow-white.png');
    }

    create ()
    {
        //  The code isn't too important for this example
        //  What we're showing here is the angles, in degrees and radians,
        //  that a Phaser sprite uses when rotating.
        //
        //  You can rotate a sprite by setting either property.
        //
        //  `angle` is in degrees, from -180 to 180.
        //  `rotation` is in radians, from -PI to PI
        //
        //  For example:
        //
        //  sprite.angle = 45
        //
        //  is the same as:
        //
        //  sprite.rotation = 0.785

        const labelStyle = { font: '16px courier', fill: '#00ff00', align: 'center' };

        //  Create a large circle, then draw the angles on it

        const circle = new Phaser.Geom.Circle(400, 300, 225);
        const labelCircle = new Phaser.Geom.Circle(400, 300, 265);

        const graphics = this.add.graphics();

        graphics.lineStyle(2, 0x00bb00, 1);

        graphics.strokeCircleShape(circle);

        graphics.beginPath();

        for (let a = 0; a < 360; a += 22.5)
        {
            graphics.moveTo(400, 300);

            const p = Phaser.Geom.Circle.CircumferencePoint(circle, Phaser.Math.DegToRad(a));

            graphics.lineTo(p.x, p.y);

            const lp = Phaser.Geom.Circle.CircumferencePoint(labelCircle, Phaser.Math.DegToRad(a));

            let na = a;

            if (a > 180)
            {
                na -= 360;
            }

            const rads = String(Phaser.Math.DegToRad(na)).substr(0, 5);
            const info = `${na}°\n${rads}`;
            const label = this.add.text(lp.x, lp.y, info, labelStyle).setOrigin(0.5);
        }

        graphics.strokePath();

        this.arrow = this.add.sprite(400, 300, 'arrow').setOrigin(0, 0.5);

        this.text = this.add.text(10, 10, '', { font: '16px Courier', fill: '#ffffff' });
    }

    update ()
    {
        this.arrow.angle += 0.2;

        this.text.setText([
            'Sprite Rotation',
            `Angle: ${this.arrow.angle.toFixed(2)}`,
            `Rotation: ${this.arrow.rotation.toFixed(2)}`
        ]);
    }
}

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

const game = new Phaser.Game(config);

Два свойства, одна цель

В Phaser каждый Sprite (и любой Game Object) имеет два свойства, управляющие его поворотом. Они взаимосвязаны, но используют разные единицы измерения, что может сбивать с толку новичков.

Свойство angle работает с привычными градусами. Его диапазон значений — от -180 до 180 градусов. Установка этого свойства автоматически пересчитывает внутреннее свойство rotation.

Свойство rotation работает с радианами. Это стандартная единица для математических вычислений в программировании, особенно в тригонометрии. Его диапазон — от -PI до PI (примерно от -3.14 до 3.14). Изменение rotation так же обновляет значение angle.

Эти два свойства — две стороны одной медали. Phaser позволяет использовать ту, которая удобнее в конкретной ситуации.

Визуализация углов на сцене

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

Сначала создаётся зелёный круг с помощью Phaser.Geom.Circle. Второй, больший круг (labelCircle) служит для позиционирования текстовых меток.

const circle = new Phaser.Geom.Circle(400, 300, 225);
const labelCircle = new Phaser.Geom.Circle(400, 300, 265);

Затем в цикле от 0 до 360 градусов с шагом 22.5 рисуются лучи от центра к окружности и добавляются подписи. Ключевой метод Phaser.Geom.Circle.CircumferencePoint получает точку на окружности для заданного угла.

const p = Phaser.Geom.Circle.CircumferencePoint(circle, Phaser.Math.DegToRad(a));

Обратите внимание на преобразование градусов в радианы с помощью Phaser.Math.DegToRad. Это необходимо, потому что большинство геометрических методов Phaser, включая CircumferencePoint, ожидают углы в радианах. Для отображения текст метки формируется из градусов и их радианного эквивалента.

Спрайт в действии

В центре визуализации размещается спрайт стрелки. Важный момент — установка точки привязки (origin). По умолчанию она в центре спрайта (0.5, 0.5), но для вращения, как у часовой стрелки, её сдвигают к началу изображения.

this.arrow = this.add.sprite(400, 300, 'arrow').setOrigin(0, 0.5);

Метод setOrigin(0, 0.5) устанавливает точку вращения на левом краю по горизонтали и по центру спрайта по вертикали. Теперь стрелка будет вращаться вокруг своего левого конца, как стрелка на циферблате.

В методе update происходит главное действие — непрерывное вращение. Увеличивая свойство angle на небольшую величину каждый кадр, мы создаём плавную анимацию.

this.arrow.angle += 0.2;

Одновременно в текстовом поле обновляются текущие значения обоих свойств, демонстрируя их синхронность. Увеличение angle на 0.2 градуса за кадр автоматически приводит к изменению rotation.

Какой метод использовать?

Выбор между angle и rotation зависит от контекста.

Используйте angle, когда: * Работаете с дизайнерами или редакторами уровней, где углы задаются в градусах. * Вращение интуитивно понятнее описывать градусами (например, поворот на 90°). * Задаёте статичное положение объекта.

Используйте rotation, когда: * Производите математические вычисления, особенно с тригонометрическими функциями (Math.sin, Math.cos). * Работаете с физическим движком Phaser (Arcade Physics, Matter.js), который оперирует радианами. * Нужна максимальная производительность в критичных по времени операциях (прямое присваивание радиан может быть чуть быстрее).

Помните, что установка одного свойства мгновенно обновляет другое, поэтому можно свободно смешивать их использование в коде, выбирая наиболее удобный вариант для каждой конкретной задачи.

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

Свойства angle и rotation — это мощный и гибкий дуэт для управления вращением в Phaser. Понимание их взаимосвязи и контекста использования избавит от путаницы и откроет путь к созданию сложного и красивого игрового поведения. Для экспериментов попробуйте: заменить this.arrow.angle += 0.2 на прямое изменение rotation; заставить спрайт вращаться к позиции курсора мыши, используя Math.atan2 (который возвращает угол в радианах); или привязать вращение к физической силе, используя body.angularVelocity.