О чем этот пример
В играх часто нужно создать объекты, которые сталкиваются с другими, но при этом не могут быть оттолкнутыми — например, тяжёлые валуны, столбы или часть декораций. В Phaser Arcade Physics для этого есть свойство `setPushable`. Эта статья покажет, как правильно использовать `setPushable(false)`, чтобы сделать физические тела устойчивыми к воздействию других объектов, сохраняя при этом все остальные свойства коллизий.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene {
preload() {
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.setPath('assets/sprites');
this.load.image('blockANP');
this.load.image('blockBNP');
}
create() {
this.physics.world.setBounds(0, 0, 864, 632);
this.cursors = this.input.keyboard.createCursorKeys();
this.left = this.physics.add.image(500, 196 - 16, 'blockANP').setCollideWorldBounds().setInteractive();
this.right = this.physics.add.image(600, 196 - 16, 'blockBNP').setCollideWorldBounds().setInteractive();
this.left.setBounce(0.5);
this.right.setBounce(0.5);
// If either one of these are a circle they will get pushed.
this.left.setCircle(32);
this.right.setCircle(32);
this.left.setPushable(false);
this.right.setPushable(false);
this.physics.add.collider(this.left, this.right);
}
update() {
if (this.cursors.left.isDown) {
this.left.setVelocityX(-160);
}
else if (this.cursors.right.isDown) {
this.left.setVelocityX(160);
}
else if (this.cursors.up.isDown) {
this.left.setVelocityY(-160);
}
else if (this.cursors.down.isDown) {
this.left.setVelocityY(160);
}
else {
this.left.setVelocity(0)
}
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 },
debug: true
}
},
};
const game = new Phaser.Game(config);
Что делает `setPushable`?
Метод setPushable управляет тем, может ли данное физическое тело быть оттолкнуто другим телом в результате столкновения. Когда вы устанавливаете значение false, это тело становится своеобразным «неподвижным столом» — оно участвует в столкновениях, но его скорость и позиция не изменяются под воздействием других объектов.
Однако важно помнить: если оба сталкивающихся тела имеют pushable: false, столкновение между ними не будет обрабатываться системой физики, и они могут проходить друг сквозь друга. Поэтому обычно это свойство выставляют только для одного из объектов в паре.
Настройка сцены и загрузка ассетов
В примере создаётся простая сцена с двумя спрайтами. Сначала мы настраиваем базовый URL для загрузки и загружаем два изображения.
preload() {
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.setPath('assets/sprites');
this.load.image('blockANP');
this.load.image('blockBNP');
}
Создание физических тел и настройка коллизий
В методе create мы создаём физический мир с границами и два спрайта с физикой. Ключевые шаги:
1. Создание интерактивных спрайтов с помощью this.physics.add.image.
2. Настройка отскока (setBounce) для реалистичности.
3. Важный момент: мы меняем форму коллайдера с прямоугольной по умолчанию на круглую с помощью setCircle(32). Это нужно, потому что свойство pushable для прямоугольных тел (Arcade Physics версии 3) может работать не так, как ожидается.
4. Оба тела делаем неподвижными через setPushable(false).
5. Добавляем коллидер для обработки столкновений между ними.
create() {
this.physics.world.setBounds(0, 0, 864, 632);
this.cursors = this.input.keyboard.createCursorKeys();
this.left = this.physics.add.image(500, 196 - 16, 'blockANP').setCollideWorldBounds().setInteractive();
this.right = this.physics.add.image(600, 196 - 16, 'blockBNP').setCollideWorldBounds().setInteractive();
this.left.setBounce(0.5);
this.right.setBounce(0.5);
// Если любое из этих тел будет кругом, их можно будет толкать.
this.left.setCircle(32);
this.right.setCircle(32);
this.left.setPushable(false);
this.right.setPushable(false);
this.physics.add.collider(this.left, this.right);
}
Управление одним из объектов
В методе update мы обрабатываем нажатия клавиш-стрелок, чтобы двигать левый спрайт (this.left). Обратите внимание: хотя этот спрайт и имеет setPushable(false), мы всё равно можем напрямую менять его скорость через setVelocity. Это свойство влияет только на реакцию тела при столкновениях с другими объектами.
update() {
if (this.cursors.left.isDown) {
this.left.setVelocityX(-160);
}
else if (this.cursors.right.isDown) {
this.left.setVelocityX(160);
}
else if (this.cursors.up.isDown) {
this.left.setVelocityY(-160);
}
else if (this.cursors.down.isDown) {
this.left.setVelocityY(160);
}
else {
this.left.setVelocity(0)
}
}
Конфигурация игры и физики
Здесь определяется основная конфигурация игры. Важно включить Arcade Physics и, для наглядности, отладку (debug: true), чтобы видеть границы коллайдеров.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 },
debug: true
}
},
};
const game = new Phaser.Game(config);
Что попробовать дальше
Использование setPushable(false) — простой способ создать статичные объекты, которые участвуют в физическом мире, но не сдвигаются при столкновениях. Помните про особенность с прямоугольными телами и используйте setCircle или setBody для нужной формы коллайдера. Для экспериментов попробуйте:
1. Убрать setPushable(false) у одного из тел и посмотреть, как они начнут толкать друг друга.
2. Сделать тела прямоугольными (удалив setCircle) и проверить разницу в поведении.
3. Создать сцену, где игрок (pushable: true) должен обойти препятствия (pushable: false).
