О чем этот пример
Визуальные эффекты — мощный инструмент для создания атмосферы в игре. В этом примере мы совместим физическую симуляцию системы Arcade с динамическим освещением Light2D в Phaser. Вы научитесь превращать обычный источник света в физический объект, который может отскакивать от границ мира, и создавать сложные взаимодействия с другими спрайтами, управляемыми физикой. Это открывает двери для создания уникальных механик, например, игры, где игрок управляет лучом света, или головоломок с движущимися источниками освещения.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 150 }
}
},
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('brick', ['assets/normal-maps/brick.jpg', 'assets/normal-maps/brick_n.png']);
this.load.image('phaser', 'assets/sprites/block.png');
}
function create ()
{
var brick = this.add.sprite(0, 0, 'brick');
brick.setOrigin(0);
brick.setPipeline('Light2D');
var light = this.lights.addLight(400, 200, 100).setIntensity(4);
// light.angle = 0;
// light.scaleX = 1;
// light.scaleY = 1;
// light.displayOriginX = 0.5;
// light.displayOriginY = 0.5;
this.physics.world.enable(light);
light.body.setVelocity(200, 160);
light.body.setBounce(1, 1);
light.body.setCollideWorldBounds(true);
console.log(light);
this.lights.enable().setAmbientColor(0x555555);
var logo = this.physics.add.image(300, 100, 'phaser');
logo.setVelocity(-100, 160);
logo.setBounce(1, 1);
logo.setCollideWorldBounds(true);
}
Настройка сцены и загрузка ассетов
Первым шагом является конфигурация игры. Мы используем рендерер WEBGL, так как только он поддерживает конвейер Light2D. Включаем физику Arcade с гравитацией.
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 150 }
}
},
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
В методе preload загружаем текстуры. Ключевой момент — загрузка изображения brick с двумя файлами: основным цветом и нормальной картой (normal map). Нормальная карта необходима для корректной работы динамического освещения, создавая иллюзию рельефа.
function preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('brick', ['assets/normal-maps/brick.jpg', 'assets/normal-maps/brick_n.png']);
this.load.image('phaser', 'assets/sprites/block.png');
}
Создание фона и включение освещения
В функции create мы создаём визуальную основу. Спрайт brick растягивается на весь экран и, что критически важно, для него устанавливается конвейер рендеринга Light2D. Без этого свет не будет влиять на этот объект.
var brick = this.add.sprite(0, 0, 'brick');
brick.setOrigin(0);
brick.setPipeline('Light2D');
Затем создаём источник света с помощью this.lights.addLight(). Указываем его начальные координаты, радиус и интенсивность.
var light = this.lights.addLight(400, 200, 100).setIntensity(4);
Наконец, глобально включаем систему освещения на сцене и задаём цвет окружающего (ambient) света. Это базовый уровень освещённости, который виден даже в отсутствие активных источников.
this.lights.enable().setAmbientColor(0x555555);
Превращение света в физический объект
Это самая интересная часть примера. Источник света — это не просто визуальный эффект, его можно наделить физическим телом и заставить двигаться по законам игрового мира.
Сначала активируем физическое тело для объекта light.
this.physics.world.enable(light);
Теперь у света есть свойство light.body, через которое мы можем управлять его физикой. Мы задаём ему начальную скорость, коэффициент упругости (отскока) и включаем столкновение с границами мира.
light.body.setVelocity(200, 160);
light.body.setBounce(1, 1);
light.body.setCollideWorldBounds(true);
В результате световой шар будет хаотично летать по экрану, отскакивая от его краёв, как мячик.
Добавление взаимодействующих объектов
Чтобы продемонстрировать независимость систем, мы добавляем на сцену обычный спрайт logo, который также управляется физикой Arcade. Он создаётся через фабричный метод this.physics.add.image, который сразу наделяет его телом.
var logo = this.physics.add.image(300, 100, 'phaser');
logo.setVelocity(-100, 160);
logo.setBounce(1, 1);
logo.setCollideWorldBounds(true);
Важно понимать: физические тела света и логотипа в данном примере не взаимодействуют друг с другом (для этого нужна была бы настройка коллизий). Они существуют параллельно. Логотип не отбрасывает тень и не является источником света, но он освещается движущимся источником light, так как находится на одной сцене с включённым освещением. Это создаёт динамичную и живую картинку.
Что попробовать дальше
Пример наглядно демонстрирует, как в Phaser можно совмещать, казалось бы, несовместимые системы — физику и освещение. Источник света становится полноценным объектом игрового мира. Для экспериментов попробуйте: изменить параметры света (angle, scaleX/Y) для создания конусообразных лучей; добавить коллизию между светом и другими объектами, чтобы он останавливался или менял направление при столкновении; создать несколько разноцветных световых шаров с разной физикой; или управлять светом с помощью курсора мыши, создавая подобие фонарика.
