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

В игровом мире Phaser камера — это ваш взгляд на сцену. Умение управлять ею открывает путь к созданию динамичных платформеров, изометрических проектов или просто эффектного следования за главным героем. Этот пример наглядно демонстрирует, как заставить несколько камер с разными параметрами следовать за одним спрайтом, создавая уникальные визуальные эффекты и понимание работы `Camera.startFollow`.

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

Живой запуск

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

Исходный код


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

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('CherilPerils', 'assets/tests/camera/CherilPerils.png');
        this.load.image('clown', 'assets/sprites/clown.png');
        this.iter = 3.14;
    }

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

        this.cameras.main.setSize(400, 300);

        const cam2 = this.cameras.add(400, 0, 400, 300);
        const cam3 = this.cameras.add(0, 300, 400, 300);
        const cam4 = this.cameras.add(400, 300, 400, 300);

        this.clown = this.add.image(450 + Math.cos(this.iter) * 200, 510 + Math.sin(this.iter) * 200, 'clown');

        this.cameras.main.startFollow(this.clown);

        cam2.startFollow(this.clown, false, 0.5, 0.5);
        cam3.startFollow(this.clown, false, 0.1, 0.1);
        cam4.startFollow(this.clown, false, 0.05, 0.05);
    }

    update ()
    {
        this.clown.x = 450 + Math.cos(this.iter) * 200;
        this.clown.y = 510 + Math.sin(this.iter) * 200;

        this.iter += 0.02;
    }
}

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

const game = new Phaser.Game(config);

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

В методе create() мы сначала добавляем на сцену фоновое изображение 'CherilPerils', устанавливая его начало (origin) в левый верхний угол (0,0). Это важно для правильного позиционирования фона относительно мировых координат.

Затем мы настраиваем главную камеру (this.cameras.main), уменьшая её область просмотра до 400x300 пикселей. По умолчанию она занимает весь холст игры (800x600). После этого создаются три дополнительные камеры с помощью метода this.cameras.add(). Каждая получает свои координаты и размеры, что позволяет разделить экран на четыре квадранта.

this.add.image(0, 0, 'CherilPerils').setOrigin(0);
this.cameras.main.setSize(400, 300);
const cam2 = this.cameras.add(400, 0, 400, 300);
const cam3 = this.cameras.add(0, 300, 400, 300);
const cam4 = this.cameras.add(400, 300, 400, 300);

Создание и привязка спрайта для слежения

В этой же функции создаётся спрайт клоуна (this.clown). Его начальная позиция вычисляется с помощью тригонометрических функций Math.cos и Math.sin от переменной this.iter, что сразу задаёт ему круговое движение.

Ключевой момент — вызов метода startFollow() у каждой камеры. Все четыре камеры начинают следовать за одним и тем же объектом — спрайтом клоуна. Разница между ними — в параметрах линейной интерполяции (LERP).

this.clown = this.add.image(450 + Math.cos(this.iter) * 200, 510 + Math.sin(this.iter) * 200, 'clown');
this.cameras.main.startFollow(this.clown);
cam2.startFollow(this.clown, false, 0.5, 0.5);
cam3.startFollow(this.clown, false, 0.1, 0.1);
cam4.startFollow(this.clown, false, 0.05, 0.05);

Главная камера (левый верхний квадрант) следует за клоуном мгновенно (по умолчанию). Второй аргумент false отключает следование с резкой остановкой у границ. Третий и четвёртый аргументы (lerpX и lerpY) определяют скорость "догоняния". Чем меньше значение (как у cam4 — 0.05), тем плавнее и с большей задержкой камера будет следовать за целью.

Анимация движения цели

Чтобы цель для камер не стояла на месте, её движение обновляется в методе update(), который вызывается на каждом кадре. Мы пересчитываем координаты this.clown по формуле круга, используя ту же переменную this.iter. Её инкремент на 0.02 каждые 60 FPS определяет скорость движения по окружности.

Этот непрерывный цикл движения и является причиной того, что камеры постоянно находятся в процессе "следования", наглядно демонстрируя разницу в их скорости реакции из-за разных коэффициентов lerp.

update ()
{
    this.clown.x = 450 + Math.cos(this.iter) * 200;
    this.clown.y = 510 + Math.sin(this.iter) * 200;
    this.iter += 0.02;
}

Практическое применение и настройки

Разделение экрана на несколько камер с разным поведением — мощный инструмент отладки или создания игровых механик. Например, так можно реализовать: * **Систему "пип-окна"** для разделенного экрана в кооперативной игре. * **Миникарту** в углу экрана, которая плавно следует за игроком. * **Эффект "дрожащей" или отстающей камеры** для передачи скорости или удара.

Ключевые параметры метода startFollow(): * lerpX, lerpY: от 0 (полное отставание) до 1 (мгновенное следование). * Второй аргумент: true включает остановку камеры у границ мира, что полезно для платформеров с ограниченным уровнем.

// Пример: камера для миникарты с плавным движением и остановкой у краёв уровня
const miniMapCam = this.cameras.add(600, 450, 180, 120);
miniMapCam.startFollow(playerSprite, true, 0.2, 0.2);

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

Камеры в Phaser — это не просто "окно в мир", а полноценные объекты с состоянием и поведением. Управляя их слежением, вы напрямую влияете на восприятие игроком скорости, масштаба и динамики происходящего. Для экспериментов попробуйте: изменить формулу движения спрайта на зигзаг или прыжки; задать разный lerp для осей X и Y, создав эффект инерции; или привязать одну камеру не к спрайту, а к точке между несколькими игроками.