О чем этот пример
В играх часто требуется анимировать объекты, которые при этом должны сохранять физические свойства и корректно сталкиваться с другими телами. Прямая анимация спрайта через `tweens` или `timeline` не обновляет физическое тело, что приводит к прохождению объектов друг сквозь друга. В этой статье разберем, как правильно анимировать физическое тело с помощью твинов в Arcade Physics, чтобы коллизии обрабатывались корректно. Этот подход полезен для создания движущихся платформ, врагов, патрулирующих территорию, или любых интерактивных анимированных препятствий.
Версия 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.image('block', 'assets/sprites/block.png');
this.load.image('dude', 'assets/sprites/phaser-dude.png');
}
create ()
{
// this.physics.world.OVERLAP_BIAS = 8;
const block = this.physics.add.image(400, 200, 'block');
block.body.allowGravity = false;
block.body.immovable = true;
block.body.moves = false;
const sprite = this.physics.add.image(400, 100, 'dude');
this.tweens.add({
targets: block,
y: 400,
duration: 2000,
ease: 'Sine.easeInOut',
repeat: -1,
yoyo: true
});
this.physics.add.collider(sprite, block);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
debug: true,
gravity: { y: 300 },
overlapBias: 8
}
},
scene: Example
};
const game = new Phaser.Game(config);
Проблема: анимация спрайта vs анимация тела
По умолчанию, когда вы применяете твин к игровому объекту (Game Object), он изменяет его свойства, такие как `x,y,scale. Однако, если этот объект также является физическим телом (например, создан черезthis.physics.add.image), система физики Arcade вычисляет положение и коллизии, основываясь на отдельном свойствеbody`. При стандартной анимации спрайта, физическое тело может "отставать" или вообще не обновлять свою позицию, что приводит к некорректным столкновениям.
Ключевой момент: чтобы анимированное тело корректно сталкивалось, нужно анимировать именно его физическое тело или использовать специальные настройки для синхронизации.
Решение: твин тела и настройка overlapBias
В предоставленном примере реализовано корректное решение. Давайте разберем его по шагам.
Сначала создается статичный блок и управляемый спрайт. Обратите внимание на настройки тела блока:
const block = this.physics.add.image(400, 200, 'block');
block.body.allowGravity = false;
block.body.immovable = true;
block.body.moves = false;
Здесь immovable: true указывает, что при столкновении этот объект не будет отталкиваться (как массивная платформа). moves: false отключает расчет движения силами физики для этого тела, что важно, так как его движением будет управлять твин.
Затем к объекту block применяется твин, который анимирует его свойство `y`:
this.tweens.add({
targets: block,
y: 400,
duration: 2000,
ease: 'Sine.easeInOut',
repeat: -1,
yoyo: true
});
Phaser 3 автоматически синхронизирует позицию спрайта и его Arcade Physics тело, когда тело имеет флаг moves = false. Это означает, что твин, изменяя block.y, также обновит block.body.y, и коллайдер будет двигаться вместе с визуальным представлением.
Наконец, создается коллайдер между спрайтом и блоком:
this.physics.add.collider(sprite, block);
Особое внимание стоит обратить на настройку overlapBias в конфигурации физики. В коде примера она задана равной 8. Эта настройка помогает системе более агрессивно корректировать позиции объектов при обработке перекрытия (overlap), что особенно важно для быстро движущихся тел.
physics: {
default: 'arcade',
arcade: {
debug: true,
gravity: { y: 300 },
overlapBias: 8 // Важная настройка для движущихся тел
}
}
Важные свойства физического тела для анимации
Для успешного совмещения твинов и физики необходимо правильно настроить тело.
* **body.moves**: Установка в false — это ключ. Тело не будет управляться скоростью или ускорением движка физики. Вместо этого его позиция может быть установлена напрямую (в нашем случае — твином), и система коллизий будет учитывать это новое положение.
* **body.immovable**: Если ваш анимированный объект должен оставаться на месте при столкновении (например, движущаяся платформа), установите это свойство в true. В противном случае при столкновении оба тела будут рассчитывать отскок, что может привести к неожиданному поведению.
* **body.allowGravity**: Обычно для анимированных платформ гравитацию отключают.
Эти три свойства часто идут вместе в подобных сценариях.
// Типичная конфигурация тела для анимированной платформы
platform.body.allowGravity = false;
platform.body.immovable = true;
platform.body.moves = false;
Альтернативный подход: твин свойства body.y
Хотя в данном примере твин применяется к самому игровому объекту, вы также можете анимировать свойства его тела напрямую. Это может быть полезно для более явного контроля.
this.tweens.add({
targets: block.body,
y: 400,
duration: 2000,
ease: 'Sine.easeInOut',
repeat: -1,
yoyo: true
});
Однако при таком подходе визуальная позиция спрайта (block.y) не будет обновляться автоматически. Вам потребуется синхронизировать ее вручную, например, в методе update() сцены:
update() {
block.y = block.body.y;
}
Поэтому первый подход (твин объекта с moves: false) является более предпочтительным и идиоматичным для Phaser 3, так как движок берет синхронизацию на себя.
Что попробовать дальше
Анимация физических тел через твины в Phaser — мощный прием для создания динамичной игровой среды. Ключевые шаги: создать тело с moves: false, применить твин к игровому объекту и настроить overlapBias для более точных коллизий. Для экспериментов попробуйте: создать сложный маршрут движения через timeline, анимировать группу тел одновременно, изменить overlapBias на лету и посмотреть на разницу в поведении столкновений или использовать этот метод для создания движущихся врагов, которые отталкивают игрока.
