О чем этот пример
При разработке игр часто требуется создать статичное препятствие или платформу. В Arcade Physics Phaser для этого есть свойство `immovable`. Однако в версии 3.60 был обнаружен баг (#7054), при котором круговые тела (`setCircle`) с этим свойством не работали корректно при столкновениях. Эта статья разбирает пример кода, демонстрирующий проблему и её автоматическое исправление в более поздних версиях движка. Понимание этой механики полезно для создания стабильных физических взаимодействий.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class MainScene extends Phaser.Scene
{
constructor()
{
super({ key: "MainScene" });
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('mushroom', 'assets/sprites/mushroom2.png');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
const mushroom = this.physics.add.image(200, 350, 'mushroom')
.setCircle(30)
.setImmovable(true);
const block = this.physics.add.image(500, 300, 'block')
.setVelocity(-100, 0)
.setBounce(1)
.setCollideWorldBounds(true);
this.physics.add.collider(mushroom, block);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
debug: true,
}
},
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH
},
scene: [ MainScene ]
};
const game = new Phaser.Game(config);
Суть проблемы: недвижимое ≠ неподвижное
Свойство .setImmovable(true) не делает тело абсолютно статичным. Вместо этого оно указывает физическому движку, что при столкновении это тело не должно получать импульс от удара. Его скорость и положение не пересчитываются. Однако другое тело (подвижное) должно от него оттолкнуться.
В баге #7054 круглое тело с immovable: true игнорировало столкновения: подвижный объект просто проходил сквозь него. Это нарушало базовую логику игровой физики.
Разбор примера: настройка сцены
В методе preload загружаются два изображения, которые будут использоваться как спрайты с физическими телами.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('mushroom', 'assets/sprites/mushroom2.png');
this.load.image('block', 'assets/sprites/block.png');
}
Создание физических тел
В методе create создаются два физических тела. Ключевой момент: гриб (mushroom) делается недвижимым и его хитбокс задаётся в виде круга. Блок (block) получает начальную скорость.
const mushroom = this.physics.add.image(200, 350, 'mushroom')
.setCircle(30)
.setImmovable(true);
const block = this.physics.add.image(500, 300, 'block')
.setVelocity(-100, 0)
.setBounce(1)
.setCollideWorldBounds(true);
Вызов .setCircle(30) заменяет прямоугольный хитбокс спрайта на круговой с радиусом 30 пикселей. Блок настроен отскакивать от границ мира (setCollideWorldBounds) и от других тел (setBounce(1)) без потери энергии.
Настройка коллизии
Столкновение между телами регистрируется с помощью this.physics.add.collider. Это главный метод для обработки отскоков и наложения в Arcade Physics.
this.physics.add.collider(mushroom, block);
При исправленном поведении (после версии 3.60) блок должен отскакивать от недвижимого гриба, как от стены. В багнутой версии коллайдер не срабатывал для кругового immovable тела.
Конфигурация игры и физики
В конфиге игры критически важно включить Arcade Physics и режим отладки debug: true. Он рисует хитбоксы тел, позволяя визуально убедиться, что коллизия работает (зелёная окружность у гриба и синий прямоугольник у блока).
physics: {
default: 'arcade',
arcade: {
debug: true, // Визуализация хитбоксов
}
}
Что попробовать дальше
Баги в низкоуровневых системах, вроде физики, могут кардинально ломать геймплей. Пример с недвижимым кругом — отличный урок: всегда тестируйте специфические комбинации свойств (setCircle + setImmovable). Для экспериментов попробуйте изменить радиус круга, убрать setImmovable или заменить круг на прямоугольный хитбокс (setSize), чтобы увидеть разницу в поведении. Актуальные версии Phaser (3.60+) содержат исправление этого бага, и столкновения работают корректно.
