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

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

Версия 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('map', 'assets/tests/camera/earthbound-scarab.png');
    }

    create () 
    {
        this.cameras.main.setBounds(0, 0, 1024, 2048);
    
        this.add.image(0, 0, 'map').setOrigin(0);
    
        this.cameras.main.setZoom(4);
        this.cameras.main.centerOn(0, 0);
    
        console.log(this.cameras.main.getScroll(767, 1096));
        
        this.text = this.add.text(304, 230).setText('Click to move').setScrollFactor(0);
        this.text.setShadow(1, 1, '#000000', 2);
    
        let pos = 0;
    
        this.input.on('pointerdown', function () {
    
            const cam = this.cameras.main;
    
            if (pos === 0)
            {
                cam.pan(767, 1096, 2000, 'Power2');
                pos++;
            }
            else if (pos === 1)
            {
                cam.pan(703, 1621, 2000, 'Elastic');
                pos++;
            }
            else if (pos === 2)
            {
                cam.pan(256, 623, 2000, 'Sine.easeInOut');
                pos++;
            }
            else if (pos === 3)
            {
                cam.pan(166, 304, 2000);
                pos++;
            }
            else if (pos === 4)
            {
                cam.pan(624, 158, 2000);
                pos++;
            }
            else if (pos === 5)
            {
                cam.pan(680, 330, 2000);
                pos++;
            }
            else if (pos === 6)
            {
                cam.pan(748, 488, 2000);
                pos++;
            }
            else if (pos === 7)
            {
                cam.pan(1003, 1719, 2000);
                pos = 0;
            }
    
        }, this);
    }

    update () 
    {
        const cam = this.cameras.main;
        this.text.setText(['Click to move', 'x: ' + cam.scrollX, 'y: ' + cam.scrollY ]);
    }
}

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

const game = new Phaser.Game(config);

Настройка мира и камеры

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

Затем мы добавляем фоновое изображение-карту и настраиваем начальное состояние основной камеры. Увеличение (setZoom) помогает сфокусироваться на конкретной стартовой области.

this.cameras.main.setBounds(0, 0, 1024, 2048);
this.add.image(0, 0, 'map').setOrigin(0);
this.cameras.main.setZoom(4);
this.cameras.main.centerOn(0, 0);

Как работает метод pan()

Метод pan() объекта камеры — это основное средство для плавного перемещения. Он анимирует изменение свойств scrollX и scrollY, отвечающих за положение камеры в мире.

Метод принимает несколько аргументов: - **x, y**: Целевые координаты в мировом пространстве, к которым нужно переместить центр камеры. - **duration**: Длительность анимации в миллисекундах. - **ease**: Необязательный параметр. Строка с названием функции плавности (easing function), которая определяет характер движения (линейный, упругий, с ускорением и т.д.). Если не указан, используется линейная интерполяция ('Linear').

Вот пример вызова с разными функциями плавности:

// Плавное движение с функцией 'Power2'
cam.pan(767, 1096, 2000, 'Power2');

// Упругое движение с отскоком в конце ('Elastic')
cam.pan(703, 1621, 2000, 'Elastic');

// Движение с плавным ускорением и замедлением ('Sine.easeInOut')
cam.pan(256, 623, 2000, 'Sine.easeInOut');

Организация интерактивного перехода

В примере переходы между точками активируются по клику мыши. Для этого используется слушатель события pointerdown. Состояние, определяющее, к какой точке двигаться дальше, хранится в переменной pos. Этот простой конечный автомат последовательно перебирает заранее заданные координаты.

Текст с координатами камеры (scrollX, scrollY) обновляется в методе update() каждый кадр, что дает игроку визуальную обратную связь. Важно отметить, что сам текст имеет setScrollFactor(0), что делает его статичным относительно экрана, а не мира.

this.input.on('pointerdown', function () {
    const cam = this.cameras.main;
    if (pos === 0) {
        cam.pan(767, 1096, 2000, 'Power2');
        pos++;
    }
    // ... другие условия
}, this);

Функции плавности (Easing)

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

- **'Linear'**: Равномерное движение без ускорения. - **'Power2' (и другие 'PowerN')**: Движение с ускорением. Число указывает на степень кривой. - **'Elastic'**: Создает эффект упругости с несколькими колебаниями в конце. - **'Sine.easeInOut'**: Плавное начало и плавный конец, выглядит очень естественно.

Полный список доступных функций можно найти в документации Phaser по Tween. Используйте разные варианты, чтобы передать нужное настроение: 'Elastic' для комичных или "пружинистых" действий, 'Sine.easeInOut' для плавных и спокойных переходов.

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

Метод cameras.main.pan() — это мощный и простой инструмент для создания управляемых переходов камеры. Он оживляет игровой мир, направляет внимание игрока и добавляет игре полировки. Для экспериментов попробуйте: 1. Связать панорамирование не с кликом, а с достижением игроком определенной точки на карте. 2. Использовать событие camera.on('camerapancomplete', callback) для запуска диалога или следующего действия после завершения движения. 3. Комбинировать pan() с методами zoom() и rotate() для создания сложных кинематографичных кадров.