О чем этот пример
В играх с несколькими сценами или уровнями часто нужно, чтобы фон жил своей жизнью, создавая ощущение глубины и динамики. Прямой вызов анимации в `update()` основной сцены может привести к путанице и проблемам с производительностью. В этой статье мы разберем, как правильно вынести анимацию фоновых элементов, например, движущегося солнца, в отдельную сцену (`Scene`). Это делает код чище, управление проще, а также позволяет независимо контролировать область видимости (`viewport`) для каждого слоя графики.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class SceneB extends Phaser.Scene {
constructor ()
{
super('SceneB');
this.sun;
}
create ()
{
this.cameras.main.setViewport(0, 136, 1024, 465);
this.sun = this.add.image(900, 80, 'space', 'sun');
}
update (time, delta)
{
this.sun.x -= 0.02 * delta;
this.sun.y += 0.015 * delta;
if (this.sun.y >= 630)
{
this.sun.setPosition(1150, -190);
}
}
}
Зачем нужны отдельные сцены для фона?
Сцена (Scene) в Phaser — это не просто экран уровня. Это самостоятельный контейнер с собственными методами create(), update() и набором объектов. Использование отдельной сцены для фоновой анимации дает несколько преимуществ:
* **Изоляция логики:** Код, отвечающий за движение солнца, не смешивается с логикой игрока или врагов.
* **Контроль области отрисовки:** Камера сцены может иметь свой viewport, что позволяет размещать анимированный фон только в нужной части экрана.
* **Производительность:** Вы можете приостанавливать или полностью выключать обновление фоновой сцены, если она не нужна, без влияния на остальную игру.
* **Переиспользование:** Такую сцену с анимацией неба или параллакс-эффектом легко подключить к нескольким игровым уровням.
Создание сцены и настройка области видимости
В конструкторе мы задаем системный ключ сцены. В методе create(), который вызывается один раз при старте сцены, происходит ключевая настройка: мы определяем, какая часть общего холста игры будет отведена под эту сцену. Это и есть viewport.
constructor ()
{
super('SceneB'); // Системное имя сцены
this.sun; // Объявляем свойство для хранения спрайта
}
create ()
{
// Устанавливаем область видимости: X=0, Y=136, ширина=1024, высота=465
this.cameras.main.setViewport(0, 136, 1024, 465);
// Создаем изображение солнца из атласа 'space' с ключом 'sun'
this.sun = this.add.image(900, 80, 'space', 'sun');
}
Здесь this.cameras.main.setViewport(0, 136, 1024, 465) говорит движку: «Рисуй содержимое этой сцены в прямоугольнике, начинающемся на 136 пикселей от верхнего края, на всю ширину окна (1024px) и высотой 465px». Объекты, выходящие за эти границы, обрезаются. Солнце создается как обычное изображение из атласа.
Анимация в методе update и "телепортация"
Сердце анимации — метод update(time, delta). Он вызывается на каждом кадре игры. Параметр delta — это время, прошедшее с предыдущего кадра в миллисекундах. Умножение скорости на delta делает движение плавным и независимым от частоты кадров (FPS).
update (time, delta)
{
// Двигаем солнце влево и вниз со скоростью, зависящей от времени кадра
this.sun.x -= 0.02 * delta;
this.sun.y += 0.015 * delta;
// Условие «ухода за экран»
if (this.sun.y >= 630)
{
// «Телепортируем» солнце обратно в начальную позицию за пределами экрана
this.sun.setPosition(1150, -190);
}
}
Код this.sun.x -= 0.02 * delta означает: «Каждую миллисекунду сдвигай солнце влево на 0.02 пикселя». Когда солнце опускается ниже условной линии (Y >= 630), оно мгновенно перемещается методом setPosition в правый верхний угол за границей viewport, создавая эффект бесконечного цикла (восход -> движение по небу -> сброс).
Как запустить фоновую сцену из основной
Чтобы эта анимация работала, фоновую сцену нужно запустить параллельно с вашей основной игровой сценой (например, GameScene). Это делается в конфигурации игры при ее запуске.
// Пример конфигурации игры (файл main.js или game.js)
const config = {
// ... другие настройки (тип, ширина, высота)
scene: [SceneB, GameScene] // SceneB (фон) будет запущена первой
};
const game = new Phaser.Game(config);
Порядок в массиве scene важен. Сцена, указанная первой (SceneB), будет отрисована первой, то есть окажется на заднем плане. Основная GameScene отрисуется поверх нее, благодаря чему игровые объекты будут на переднем плане.
Что попробовать дальше
Вынос анимации фона в отдельную сцену — это мощный паттерн в Phaser для создания сложных многослойных визуальных эффектов. Он обеспечивает чистоту кода и гибкость управления. Для экспериментов попробуйте: добавить второе светило (луну) с другой траекторией в этой же сцене; изменить логику «телепортации» на плавное появление с другой стороны; или создать несколько фоновых сцен с разной скоростью движения (параллакс-эффект), управляя их скоростью через delta.
