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

Работа с текстом и камерой — основа интерфейсов и визуальных эффектов в играх. В этом примере из официальной коллекции Phaser показано, как создать динамический текст с эффектом параллакса и управлять камерой с плавной инерцией. Это полезно для создания меню, титров или любого текстового контента, который должен реагировать на движение камеры, добавляя игре глубины и динамики. Вы научитесь использовать `DynamicBitmapText` для отображения текста, настраивать его `scrollFactor` и управлять камерой через `SmoothedKeyControl` для профессионального ощущения от управления.

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

Живой запуск

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

Исходный код


let controls;
class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.bitmapFont('ice', 'assets/fonts/bitmap/iceicebaby.png', 'assets/fonts/bitmap/iceicebaby.xml');
    }

    create ()
    {
        const sf = 1 / 16;

        for (var i = 0; i < 16; i++)
        {
            this.add.dynamicBitmapText(200, 300, 'ice', 'Phaser 3', 128).setScrollFactor(sf * i);
        }

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

        const controlConfig = {
            camera: this.cameras.main,
            left: cursors.left,
            right: cursors.right,
            up: cursors.up,
            down: cursors.down,
            zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
            zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
            acceleration: 0.03,
            drag: 0.0005,
            maxSpeed: 0.5
        };

        this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
    }

    update (time, delta)
    {
        this.controls.update(delta);
    }
}

const config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    backgroundColor: '#2d2d2d',
    roundPixels: true,
    scene: Example
};


const game = new Phaser.Game(config);

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

В классе Example, расширяющем Phaser.Scene, в методе constructor вызывается родительский конструктор. Это стандартная практика для сцен Phaser.

В методе preload загружается bitmap-шрифт. Важно использовать setBaseURL, чтобы указать базовый путь для ресурсов. Шрифт 'ice' состоит из двух файлов: изображения (.png) и файла описания (.xml).

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.bitmapFont('ice', 'assets/fonts/bitmap/iceicebaby.png', 'assets/fonts/bitmap/iceicebaby.xml');
}

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

В методе create создается основной визуальный эффект. Используется цикл for, который создает 16 идентичных объектов динамического bitmap-текста. Каждый объект выводит строку 'Phaser 3' с размером 128 пикселей.

Ключевой параметр — setScrollFactor(sf * i). ScrollFactor определяет, насколько быстро объект движется относительно камеры. Значение 0 означает, что объект зафиксирован на экране. Значение 1 означает, что он движется с той же скоростью, что и камера. В примере используется обратная прогрессия: первый слой текста (i=0) имеет множитель 0, последний (i=15) — почти 1. Это создает эффект параллакса, где слои текста движутся с разной скоростью при перемещении камеры.

create ()
{
    const sf = 1 / 16;
    for (var i = 0; i < 16; i++)
    {
        this.add.dynamicBitmapText(200, 300, 'ice', 'Phaser 3', 128).setScrollFactor(sf * i);
    }

Настройка плавного управления камерой

Далее в create настраивается управление камерой. Сначала создается объект cursors для отслеживания стрелок клавиатуры.

Затем создается конфигурационный объект controlConfig для контроллера SmoothedKeyControl. В него передается: - camera: основная камера сцены. - Клавиши для движения (left, right, up, down). - Клавиши `QиEдля зума (zoomIn,zoomOut`). - Параметры acceleration (ускорение), drag (сопротивление) и maxSpeed (максимальная скорость). Эти значения обеспечивают плавное, инерционное движение камеры.

Контроллер создается и сохраняется в свойстве сцены this.controls.

const cursors = this.input.keyboard.createCursorKeys();
    const controlConfig = {
        camera: this.cameras.main,
        left: cursors.left,
        right: cursors.right,
        up: cursors.up,
        down: cursors.down,
        zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
        zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
        acceleration: 0.03,
        drag: 0.0005,
        maxSpeed: 0.5
    };
    this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
}

Обновление состояния контроллера

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

update (time, delta)
{
    this.controls.update(delta);
}

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

Объект config содержит базовые настройки игры. Здесь используется рендерер Phaser.CANVAS. Установка roundPixels: true помогает избежать размытия пикселей при отрисовке. Сцена Example передается в конфигурацию. Игра создается с этими настройками.

const config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    backgroundColor: '#2d2d2d',
    roundPixels: true,
    scene: Example
};
const game = new Phaser.Game(config);

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

Этот пример демонстрирует мощную, но простую комбинацию DynamicBitmapText с параллаксом и плавного управления камерой. Для экспериментов попробуйте: изменить количество слоев текста и формулу расчета scrollFactor для другого визуального эффекта; заменить текст или шрифт; настроить параметры acceleration, drag и maxSpeed в контроллере камеры для изменения 'ощущения' управления; добавить другие объекты с разными scrollFactor, чтобы создать сложную многослойную сцену.