Встроенные события World: postStep, addBody, removeBody

Библиотека Cannon.js предоставляет мощный движок физики для JavaScript с поддержкой жестких тел, столкновений и динамики. Важным элементом работы является объект World, который управляет симуляцией и хранит все тела сцены. Одной из ключевых возможностей является использование встроенных событий, позволяющих реагировать на изменения мира и управлять телами динамически.


Событие postStep

Событие postStep вызывается после каждого шага симуляции мира. Этот механизм обеспечивает выполнение кода после того, как все физические расчеты текущего кадра завершены.

Синтаксис:

world.addEventListener('postStep', function(event) {
    // Код, выполняющийся после шага симуляции
});

Особенности:

  • Позволяет безопасно изменять объекты мира без нарушения текущей симуляции.
  • Используется для обновления визуализации объектов, синхронизации с рендером.
  • Подходит для реализации ограничителей, силовых полей или скриптов, зависящих от итогового состояния тел.

Пример применения:

const world = new CANNON.World();
world.broadphase = new CANNON.NaiveBroadphase();
world.gravity.set(0, -9.82, 0);

world.addEventListener('postStep', () => {
    world.bodies.forEach(body => {
        if (body.position.y < 0) {
            body.position.y = 5; // возвращаем тело на стартовую высоту
        }
    });
});

const sphereBody = new CANNON.Body({
    mass: 1,
    shape: new CANNON.Sphere(1)
});
world.addBody(sphereBody);

function simulate() {
    world.step(1/60);
    requestAnimationFrame(simulate);
}
simulate();

В этом примере каждое тело, упавшее ниже уровня y=0, возвращается на высоту 5 единиц после завершения шага физики.


Событие addBody

Событие addBody срабатывает при добавлении тела в мир. Оно полезно для логирования, динамического изменения свойств или запуска связанных процессов при добавлении новых объектов.

Синтаксис:

world.addEventListener('addBody', function(event) {
    const body = event.body;
    // Действия с добавленным телом
});

Особенности:

  • event.body содержит ссылку на добавляемое тело.
  • Можно проверять свойства тела и автоматически применять настройки (массу, материалы, коллайдеры).
  • Позволяет интегрировать динамическую логику добавления объектов в симуляцию без необходимости вручную отслеживать каждое тело.

Пример использования:

world.addEventListener('addBody', (event) => {
    console.log(`Тело добавлено: масса = ${event.body.mass}`);
    if (event.body.mass > 10) {
        event.body.linearDamping = 0.9; // уменьшение скорости для тяжелых тел
    }
});

const boxBody = new CANNON.Body({
    mass: 12,
    shape: new CANNON.Box(new CANNON.Vec3(1, 1, 1))
});
world.addBody(boxBody);

Здесь при добавлении коробки автоматически устанавливается демпфирование, если масса превышает пороговое значение.


Событие removeBody

Событие removeBody срабатывает при удалении тела из мира. Это позволяет корректно управлять ресурсами и реализовать дополнительные действия при удалении объектов.

Синтаксис:

world.addEventListener('removeBody', function(event) {
    const body = event.body;
    // Очистка ресурсов или обновление логики
});

Особенности:

  • event.body возвращает удаляемое тело.
  • Полезно для освобождения памяти, удаления связанных визуальных объектов или остановки скриптов, связанных с телом.
  • Можно реализовать условное удаление с логикой, которая срабатывает до фактического удаления.

Пример применения:

world.addEventListener('removeBody', (event) => {
    console.log(`Тело удалено: ${event.body.id}`);
    if (event.body.userData) {
        // Очистка пользовательских данных
        delete event.body.userData;
    }
});

world.removeBody(boxBody);

В этом примере при удалении тела автоматически выполняется очистка пользовательских данных, связанных с объектом.


Практические советы по работе с событиями World

  1. Комбинирование событий Часто удобно сочетать addBody и removeBody с postStep, чтобы отслеживать динамическую симуляцию и управлять объектами по мере их появления и исчезновения.

  2. Избегать тяжелых вычислений в postStep Поскольку это событие вызывается каждый кадр, интенсивные операции могут замедлить симуляцию. Логичнее делать обновления только для необходимых тел.

  3. Использование пользовательских данных (userData) Каждое тело можно расширять произвольными данными для управления логикой внутри событий. Это особенно полезно при массовой симуляции объектов.

  4. Обеспечение согласованности Изменения тел внутри postStep происходят после завершения всех столкновений и интеграции. Это безопасный момент для корректировки позиции, скорости или удаления тела без риска нарушить расчет столкновений текущего кадра.


Эти события формируют основу для интерактивной и динамичной симуляции в Cannon.js, позволяя полностью контролировать создание, изменение и удаление объектов в мире, а также реагировать на каждый шаг физики с высокой точностью.