Логирование контактов и сил

Cannon.js — это мощная физическая библиотека для JavaScript, предназначенная для симуляции твёрдого тела и взаимодействий в 3D-пространстве. Одним из ключевых аспектов работы с физикой является отслеживание контактов между объектами и вычисление возникающих при этом сил. Это важно как для отладки физической симуляции, так и для создания эффектных взаимодействий, например, при столкновениях или нажатиях.


События контакта

Cannon.js использует систему событий для уведомления о взаимодействиях тел. Основные события, связанные с контактами:

  • collide — срабатывает при столкновении двух тел.
  • beginContact и endContact — используются для начала и окончания контакта (доступно через расширения или пользовательские обработчики).

Пример регистрации события collide для конкретного тела:

bodyA.addEventListener('collide', function(event) {
    const bodyB = event.body;  // Другое тело, с которым произошло столкновение
    const contact = event.contact; // Объект контакта с параметрами
    console.log('Столкновение с телом:', bodyB.id);
});

Объект contact содержит важную информацию о столкновении:

  • contact.bi и contact.bj — тела, участвующие в контакте.
  • contact.ni — нормаль столкновения, направленная от bi к bj.
  • contact.ri и contact.rj — векторы от центров масс тел до точки контакта.
  • contact.getImpactVelocityAlongNormal() — скорость сближения тел вдоль нормали.

Эти данные позволяют логировать как факт контакта, так и его динамику.


Доступ к контактной информации через World

Для глобального логирования всех контактов удобно использовать массив world.contacts, который заполняется при каждом шаге симуляции:

world.step(timeStep);

world.contacts.forEach(contact => {
    const bodyA = contact.bi;
    const bodyB = contact.bj;
    const normal = contact.ni;
    const impactVelocity = contact.getImpactVelocityAlongNormal();

    console.log(`Контакт между ${bodyA.id} и ${bodyB.id}`);
    console.log(`Нормаль: x=${normal.x}, y=${normal.y}, z=${normal.z}`);
    console.log(`Скорость сближения: ${impactVelocity}`);
});

Важно учитывать, что world.contacts доступен только после вызова world.step, так как контакты вычисляются в процессе интеграции.


Логирование сил

Для вычисления и отслеживания сил контакта можно использовать объект ContactEquation, который создаётся Cannon.js автоматически для каждого контакта. Основные свойства:

  • contactEquation.jacobianElementA и contactEquation.jacobianElementB — матрицы Якоби для тел, участвующих в контакте.
  • contactEquation.multiplier — коэффициент силы, действующей вдоль нормали.
  • contactEquation.ni — нормаль контакта.

Пример получения силы контакта для одного контакта:

bodyA.addEventListener('collide', function(event) {
    const contact = event.contact;
    const forceMagnitude = contact.getImpactVelocityAlongNormal() * contact.bi.mass;
    console.log(`Сила контакта: ${forceMagnitude.toFixed(2)}`);
});

Этот подход позволяет не только визуализировать столкновения, но и использовать силы для геймплейных эффектов: отбрасывание объектов, повреждения или звуковые эффекты.


Визуализация контактов

Для наглядного логирования контактов часто используют вспомогательные объекты, например, маленькие сферы в точках столкновения:

const sphereGeo = new THREE.SphereGeometry(0.05, 8, 8);
const sphereMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });

bodyA.addEventListener('collide', function(event) {
    const contactPoint = event.contact.rj.vadd(event.body.position);
    const sphere = new THREE.Mesh(sphereGeo, sphereMat);
    sphere.position.copy(contactPoint);
    scene.add(sphere);
});

Визуализация помогает убедиться, что расчёт нормалей и сил совпадает с ожидаемым поведением в пространстве.


Логирование для анализа производительности

В сложных симуляциях часто необходимо контролировать количество контактов и максимальные силы, чтобы избежать нестабильности:

let maxForce = 0;

world.step(timeStep);

world.contacts.forEach(contact => {
    const force = contact.getImpactVelocityAlongNormal() * contact.bi.mass;
    if(force > maxForce) maxForce = force;
});

console.log(`Максимальная сила за шаг: ${maxForce.toFixed(2)}`);

Это позволяет отлаживать параметры friction, restitution и mass тел для стабильной симуляции.


Практические рекомендации

  • Логировать только необходимые контакты, чтобы не перегружать консоль.
  • Использовать getImpactVelocityAlongNormal() для расчёта динамических эффектов, так как она учитывает относительное движение тел.
  • Для сложных симуляций с большим количеством объектов лучше агрегировать данные по шагам симуляции и выводить их после, а не при каждом столкновении.
  • Визуальные индикаторы контактных точек позволяют выявить ошибки в модели коллизий и параметрах материалов.

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