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

При разработке игр с обширными уровнями или картами часто возникает необходимость в камере, которая может следовать за игроком и одновременно масштабировать обзор. Пример bugs/6878 zoom.js демонстрирует, как в Phaser 3 настроить камеру для следования за спрайтом с сильным увеличением (зумом) в пределах огромного игрового мира. Это полезно для создания эффектов приближения, изометрических проекций или просто для детального рассмотрения действий игрока на масштабной локации. В статье мы разберем ключевые методы работы с камерой: установку границ мира, привязку к объекту, настройку "мертвой зоны" и, самое главное, управление уровнем масштабирования. Вы узнаете, как эти настройки взаимодействуют друг с другом и как их применять в своих проектах.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene {
    preload() {
        
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/pics/uv-grid-diag.png');
        this.load.image('ship', 'assets/sprites/phaser-ship.png');
    }

    create() {
        this.cameras.main.setBounds(0, 0, 1024 * 4, 1024 * 4);
        for (let y = 0; y < 4; y++) {
            for (let x = 0; x < 4; x++) {
                this.add.image(1024 * x, 1024 * y, 'bg').setOrigin(0);
            }
        }
        this.player = this.add.image(1000, 1024, 'ship');
        
        this.cameras.main.startFollow(this.player, false);
        this.cameras.main.setDeadzone(5, 5);
        this.cameras.main.setZoom(5);
        this.tweens.add({
            targets: this.player,
            x: 1300,
            yoyo: true,
            duration: 300 * 200
        });
    }

}

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

const game = new Phaser.Game(config);

Подготовка мира и создание фона

Перед настройкой камеры необходимо подготовить игровой мир. В данном примере создается большое пространство размером 4096x4096 пикселей (4x4 тайла по 1024 пикселя каждый). Это делается в методе create.

Сначала устанавливаются границы камеры с помощью setBounds. Это определяет область, за пределы которой камера не может выйти.

Затем в двойном цикле создается фон из повторяющихся изображений, чтобы заполнить всю эту область.

this.cameras.main.setBounds(0, 0, 1024 * 4, 1024 * 4);
for (let y = 0; y < 4; y++) {
    for (let x = 0; x < 4; x++) {
        this.add.image(1024 * x, 1024 * y, 'bg').setOrigin(0);
    }
}

Здесь важно свойство .setOrigin(0), которое устанавливает точку привязки изображения в его левый верхний угол. Это позволяет корректно выстраивать тайлы без зазоров.

Создание игрока и настройка следования камеры

Далее создается спрайт игрока (корабля) и помещается в определенную точку мира.

this.player = this.add.image(1000, 1024, 'ship');

Затем камера "привязывается" к этому спрайту с помощью метода startFollow. Второй параметр false отключает линейную интерполяцию (LERP), что заставляет камеру следовать за целью мгновенно, без плавного "догоняющего" эффекта.

this.cameras.main.startFollow(this.player, false);

Теперь центр камеры будет совпадать с позицией спрайта player.

Мертвая зона и увеличение (Zoom)

Ключевые настройки для создания стабильного и приятного визуального эффекта — это "мертвая зона" (Deadzone) и масштаб (Zoom).

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

this.cameras.main.setDeadzone(5, 5);

В примере установлена очень маленькая зона 5x5 пикселей, что означает, что камера начнет двигаться, как только игрок отклонится от ее центра более чем на 2.5 пикселя.

Самый эффектный метод — setZoom. Он задает уровень масштабирования камеры.

this.cameras.main.setZoom(5);

Значение `5` означает пятикратное увеличение. Все содержимое камеры (игровой мир) будет отображаться в 5 раз крупнее. Важно помнить, что при таком зуме видимая область камеры (viewport) резко уменьшается, и "мертвая зона" в 5 пикселей на экране соответствует уже 1 пикселю в игровом мире (5 / 5 = 1).

Анимация движения для демонстрации

Чтобы продемонстрировать работу камеры в действии, к спрайту игрока применяется простая твин-анимация.

this.tweens.add({
    targets: this.player,
    x: 1300,
    yoyo: true,
    duration: 300 * 200
});

Анимация плавно перемещает корабль по оси X из начальной точки 1000 в точку 1300, а затем обратно (благодаря параметру yoyo: true). Очень длинная duration (60000 мс) обеспечивает медленное, заметное движение, идеальное для наблюдения за поведением камеры с зумом.

В результате мы видим, как камера, увеличенная в 5 раз, с небольшой "мертвой зоной", плавно следует за медленно двигающимся кораблем по огромному миру, создавая эффект детального наблюдения.

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

Пример наглядно показывает мощь и гибкость системы камер Phaser 3. Комбинация setBounds, startFollow, setDeadzone и setZoom позволяет легко реализовать сложное поведение камеры, необходимое для множества жанров игр. Для экспериментов попробуйте изменить значение в setZoom на 0.5 (уменьшение), 1 (нормальный вид) или 10 (сильное увеличение). Поиграйте с размерами setDeadzone — увеличьте их до 100x100, чтобы камера двигалась только при значительном смещении игрока. Также можно включить интерполяцию в startFollow, установив второй параметр в true, и посмотреть, как изменится "ощущение" от управления.