О чем этот пример
В играх часто требуется, чтобы объекты, вылетая за границы экрана, появлялись с противоположной стороны, создавая иллюзию бесконечного пространства. Это классический приём для космических шутеров, астероидных полей или фоновых элементов. В Phaser с помощью Arcade Physics такая реализация становится элементарной задачей в одну строку кода. В этой статье мы разберём пример, который демонстрирует использование метода `world.wrap()`. Вы узнаете, как заставить спрайт с физикой непрерывно двигаться по экрану, автоматически переходя с одной границы на другую, и как тонко настроить это поведение с помощью параметра отступа.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
block;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
this.block = this.physics.add.image(0, 0, 'block').setVelocity(150, 150);
}
update ()
{
this.physics.world.wrap(this.block, 48);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade'
},
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и спрайта
Всё начинается с базовой настройки сцены. В методе preload() мы загружаем текстуру спрайта. Обратите внимание, что пример использует setBaseURL() для указания корневого пути к ассетам, что удобно для демок, но в вашем проекте, скорее всего, будет абсолютный или относительный путь.
В методе create() создаётся физический спрайт. Ключевой момент — спрайт добавляется через this.physics.add.image(), что сразу включает его в систему Arcade Physics. Мы задаём ему начальную позицию (0, 0) — левый верхний угол — и начальную скорость по обеим осям с помощью .setVelocity(150, 150).
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
this.block = this.physics.add.image(0, 0, 'block').setVelocity(150, 150);
}
Магия метода `world.wrap()`
Вся логика "заворачивания" происходит в методе update(), который вызывается на каждом кадре игры. Здесь используется метод this.physics.world.wrap().
Этот метод принимает два аргумента:
1. **gameObject**: Физический объект (в нашем случае this.block), который нужно "завернуть".
2. **padding** (опционально): Числовой отступ. Это важный параметр, который определяет, насколько далеко за границы камеры должен улететь объект, прежде чем он будет перемещён на противоположную сторону. По умолчанию значение равно 0.
В нашем примере отступ установлен в 48 пикселей. Это значит, что спрайт должен полностью исчезнуть за границей экрана (с запасом в 48 пикселей от своего края), и только тогда произойдёт его перенос.
update ()
{
this.physics.world.wrap(this.block, 48);
}
Зачем нужен параметр отступа (padding)?
Параметр padding — это не просто техническая деталь, а инструмент управления визуальным восприятием. Если установить padding: 0, объект начнёт переноситься в тот самый момент, когда его центр пересечёт границу мира. Это может выглядеть резко и неестественно, особенно для крупных спрайтов.
Установка положительного значения padding (например, равного половине ширины спрайта) гарантирует, что объект сначала *полностью* скроется за пределами экрана, и только затем появится с другой стороны. Это создаёт плавную и убедительную иллюзию бесконечного пространства. В примере значение 48, скорее всего, подобрано под размер спрайта "block" (96x96 пикселей), так как половина от 96 — это 48.
Без отступа:
this.physics.world.wrap(this.block); // или this.physics.world.wrap(this.block, 0);
С отступом, равным половине ширины спрайта:
this.physics.world.wrap(this.block, this.block.width / 2);
Конфигурация игры и физики
Для работы примера необходима правильная конфигурация игры. Самое важное — активация физического движка Arcade в настройках. Это делается в объекте config.physics.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade' // Включаем Arcade Physics как систему по умолчанию
},
scene: Example
};
const game = new Phaser.Game(config);
Без указания physics: { default: 'arcade' } вызов this.physics.add.image() вызовет ошибку, так как физическая система не будет инициализирована. Также убедитесь, что ваша сцена (в данном случае класс Example) корректно передана в конфиг.
Что попробовать дальше
Метод this.physics.world.wrap() — это элегантное и производительное решение для создания эффекта бесконечного или циклического движения объектов. Он избавляет разработчика от необходимости вручную отслеживать координаты и выполнять сложные проверки.
**Идеи для экспериментов:**
1. Примените wrap() к группе физических объектов (Phaser.Physics.Arcade.Group) и понаблюдайте за движением астероидного поля.
2. Создайте два спрайта с разной скоростью и отступом, чтобы понять, как параметры влияют на визуальный эффект.
3. Попробуйте "завернуть" объект не по всем границам, а только по горизонтали или вертикали, комбинируя wrap() с ручной проверкой координат в update().
