Реализация onContactAdded

Ammo.js — это порт библиотеки Bullet Physics на JavaScript с использованием Emscripten. Он предоставляет высокопроизводительные инструменты для реализации динамической физики в браузере. Основные сущности движка включают мир (dynamicsWorld), тела (rigidBody), формы коллизий (collisionShape) и движки столкновений (collisionDispatcher). Для работы с контактами между объектами ключевым становится механизм обратного вызова — onContactAdded.

Обратный вызов onContactAdded

onContactAdded вызывается каждый раз, когда два тела начинают контактировать. Его основной назначение — обработка информации о столкновении в реальном времени. Это может включать:

  • регистрацию столкновения для логики игры,
  • применение дополнительных сил,
  • воспроизведение звуковых или визуальных эффектов.

Подписка на этот коллбэк происходит через Ammo.custom. Прямого интерфейса в чистом Ammo.js нет, поэтому используется переопределение низкоуровневых функций btManifoldResult и contactProcessedCallback.

Пример базового шаблона:

Ammo.custom = {
    contactProcessedCallback: function(cp, body0, body1) {
        onContactAdded(cp, body0, body1);
        return false;
    }
};

function onContactAdded(cp, body0, body1) {
    const rb0 = Ammo.castObject(body0, Ammo.btRigidBody);
    const rb1 = Ammo.castObject(body1, Ammo.btRigidBody);

    const pos0 = rb0.getCenterOfMassPosition();
    const pos1 = rb1.getCenterOfMassPosition();

    console.log("Контакт между телами:", rb0, rb1);
    console.log("Позиции тел:", pos0.x(), pos0.y(), pos0.z(), pos1.x(), pos1.y(), pos1.z());
}

Параметры функции

  • cp — структура btManifoldPoint, содержащая точку контакта, нормаль и силу столкновения.
  • body0, body1 — объекты btCollisionObject, участвующие в контакте.

Из btManifoldPoint можно получить:

  • точку контакта в мире: cp.getPositionWorldOnA(), cp.getPositionWorldOnB(),
  • нормаль столкновения: cp.m_normalWorldOnB,
  • сила импульса: cp.getAppliedImpulse().

Практическое использование

  1. Определение столкновений между конкретными типами объектов
function onContactAdded(cp, body0, body1) {
    const type0 = body0.getUserIndex();
    const type1 = body1.getUserIndex();

    if ((type0 === 1 && type1 === 2) || (type0 === 2 && type1 === 1)) {
        applySpecialEffect(cp, body0, body1);
    }
}
  1. Влияние на физику после контакта

Можно изменять массу, коэффициент трения или добавлять импульс при столкновении:

function applyImpulse(body, impulseVector) {
    const rb = Ammo.castObject(body, Ammo.btRigidBody);
    const impulse = new Ammo.btVector3(impulseVector.x, impulseVector.y, impulseVector.z);
    rb.applyImpulse(impulse, new Ammo.btVector3(0,0,0));
    Ammo.destroy(impulse);
}
  1. Сбор статистики столкновений

onContactAdded идеально подходит для подсчета количества контактов на кадр, определения зон с высокой нагрузкой или логики разрушений объектов.

let contactsPerFrame = 0;

function onContactAdded(cp, body0, body1) {
    contactsPerFrame++;
}

Ограничения и особенности

  • onContactAdded срабатывает только на начальных фазах контакта. Для непрерывного мониторинга контактов нужно использовать btPersistentManifold.
  • Необходимо аккуратно управлять памятью при создании btVector3 и других объектов Ammo.js, чтобы избежать утечек.
  • Функция должна возвращать false или true. true иногда используется для модификации поведения столкновения, но в большинстве случаев достаточно false.

Оптимизация

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

Взаимодействие с другими компонентами Ammo.js

  • btDispatcher — управляет всеми контактами и вызывает contactProcessedCallback.
  • btCollisionObject — объект, которому можно присвоить пользовательские индексы и идентификаторы для упрощённой логики.
  • btManifoldPoint — предоставляет детальные данные о каждом контакте, включая позиции и силы.

Использование onContactAdded позволяет создавать продвинутые механики взаимодействия объектов в браузере: от простых столкновений до сложных систем разрушений и симуляций.