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

Физика — основа динамичных игр. Phaser Arcade предоставляет простой, но мощный инструментарий для её реализации. Этот пример показывает, как создать отзывчивого персонажа с ускорением, анимацией и физическим поведением, используя всего несколько строк кода. Вы научитесь настраивать физическое тело, управлять им с клавиатуры и синхронизировать анимацию с направлением движения.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    cursors;
    dragon;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('clouds', 'assets/skies/clouds.png');
        this.load.spritesheet('dragon', 'assets/sprites/stormlord-dragon96x64.png', { frameWidth: 96, frameHeight: 64 });
    }

    create ()
    {
        this.anims.create({
            key: 'right',
            frames: this.anims.generateFrameNumbers('dragon', { start: 0, end: 5 }),
            frameRate: 12,
            repeat: -1
        });

        this.anims.create({
            key: 'left',
            frames: this.anims.generateFrameNumbers('dragon', { start: 6, end: 11 }),
            frameRate: 12,
            repeat: -1
        });

        this.add.image(400, 400, 'clouds');

        this.dragon = this.physics.add.sprite(400, 300, 'dragon')
            .play('right')
            .setBounce(0.2, 0.2)
            .setCollideWorldBounds(true)
            .setDrag(300, 300)
            .setMaxVelocity(600, 600)
            .setGravity(0, 450);

        this.cursors = this.input.keyboard.createCursorKeys();
    }

    update ()
    {
        const { left, right, up, down } = this.cursors;

        this.dragon.setAcceleration(0, 0);

        if (left.isDown)
        {
            this.dragon.setAccelerationX(-600);
        }
        else if (right.isDown)
        {
            this.dragon.setAccelerationX(600);
        }

        if (up.isDown)
        {
            this.dragon.setAccelerationY(-600);
        }
        else if (down.isDown)
        {
            this.dragon.setAccelerationY(600);
        }

        const { x } = this.dragon.body.velocity;

        if (x < 0)
        {
            this.dragon.play('left', true);
        }
        else if (x > 0)
        {
            this.dragon.play('right', true);
        }
    }
}

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

const game = new Phaser.Game(config);

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

В методе preload() мы загружаем изображение фона и спрайтшит с анимацией дракона. Обратите внимание на параметры frameWidth и frameHeight — они разбивают спрайтшит на отдельные кадры.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('clouds', 'assets/skies/clouds.png');
    this.load.spritesheet('dragon', 'assets/sprites/stormlord-dragon96x64.png', { frameWidth: 96, frameHeight: 64 });
}

Создание анимаций и физического спрайта

В методе create() мы определяем две анимации: для движения вправо (кадры 0-5) и влево (кадры 6-11). Ключевой момент — создание спрайта через this.physics.add.sprite(), который автоматически получает Arcade Physics тело.

Цепочка методов настраивает поведение дракона: - play('right') — запускает стартовую анимацию. - setBounce(0.2, 0.2) — задаёт упругость при столкновениях. - setCollideWorldBounds(true) — включает столкновение с границами мира. - setDrag(300, 300) — добавляет сопротивление, чтобы дракон не скользил вечно. - setMaxVelocity(600, 600) — ограничивает максимальную скорость. - setGravity(0, 450) — задаёт гравитацию, притягивающую спрайт вниз.

create ()
{
    this.anims.create({
        key: 'right',
        frames: this.anims.generateFrameNumbers('dragon', { start: 0, end: 5 }),
        frameRate: 12,
        repeat: -1
    });

    this.anims.create({
        key: 'left',
        frames: this.anims.generateFrameNumbers('dragon', { start: 6, end: 11 }),
        frameRate: 12,
        repeat: -1
    });

    this.add.image(400, 400, 'clouds');

    this.dragon = this.physics.add.sprite(400, 300, 'dragon')
        .play('right')
        .setBounce(0.2, 0.2)
        .setCollideWorldBounds(true)
        .setDrag(300, 300)
        .setMaxVelocity(600, 600)
        .setGravity(0, 450);

    this.cursors = this.input.keyboard.createCursorKeys();
}

Обработка ввода и управление ускорением

Метод update() вызывается каждый кадр. Здесь мы считываем состояние клавиш-стрелок и применяем ускорение к дракону. Важная деталь: в начале каждого кадра мы сбрасываем ускорение на ноль с помощью this.dragon.setAcceleration(0, 0). Это предотвращает накопление ускорения от прошлого кадра.

Затем, в зависимости от нажатой клавиши, мы устанавливаем ускорение по оси X или Y. Arcade Physics автоматически интегрирует это ускорение в скорость, а скорость — в перемещение спрайта.

update ()
{
    const { left, right, up, down } = this.cursors;

    this.dragon.setAcceleration(0, 0);

    if (left.isDown)
    {
        this.dragon.setAccelerationX(-600);
    }
    else if (right.isDown)
    {
        this.dragon.setAccelerationX(600);
    }

    if (up.isDown)
    {
        this.dragon.setAccelerationY(-600);
    }
    else if (down.isDown)
    {
        this.dragon.setAccelerationY(600);
    }
}

Синхронизация анимации со скоростью

Вторая часть метода update() отвечает за переключение анимации. Мы проверяем горизонтальную скорость тела дракона (this.dragon.body.velocity.x). Если скорость отрицательная (движемся влево), проигрываем анимацию 'left'. Если положительная (движемся вправо) — анимацию 'right'. Флаг true в методе play() означает, что если эта анимация уже проигрывается, её не нужно перезапускать. Это создаёт плавную и логичную связь между физикой и визуальным представлением.

const { x } = this.dragon.body.velocity;

    if (x < 0)
    {
        this.dragon.play('left', true);
    }
    else if (x > 0)
    {
        this.dragon.play('right', true);
    }
}

Настройка конфигурации игры

Конфигурационный объект config определяет основные параметры игры. Для работы физики Arcade важно установить physics.default в значение 'arcade'. Параметр pixelArt: true включает сглаживание текстур для пиксель-арт графики, что улучшает визуальное качество.

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

const game = new Phaser.Game(config);

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

Вы разобрали пример, который демонстрирует основу управления персонажем с физикой в Phaser. Arcade Physics позволяет легко задавать ускорение, скорость и границы, создавая реалистичное движение. Для экспериментов попробуйте изменить значения ускорения, сопротивления (drag) или гравитации, чтобы почувствовать, как они влияют на ощущения от управления. Добавьте платформы и метод collider() для создания простого платформера.