Реализация onContactDestroyed

onContactDestroyed — это коллбэк-функция, используемая внутри физического движка Ammo.js для обработки событий разрушения контакта между телами. Контакт создается, когда два объекта сталкиваются, и может быть уничтожен по различным причинам: удаление объекта из сцены, окончание коллизии или изменение физических свойств. Функция onContactDestroyed позволяет отслеживать момент прекращения взаимодействия и корректно управлять ресурсами.

Сигнатура и параметры

Функция onContactDestroyed имеет стандартную сигнатуру:

function onContactDestroyed(contactPointPtr, userData) {
    // тело функции
}
  • contactPointPtr — указатель на объект контакта в памяти Ammo.js. Через него можно получить информацию о телах и точках взаимодействия.
  • userData — дополнительная информация, переданная при регистрации коллбэка. Обычно используется для связывания контакта с объектами игры или логики сцены.

Важно понимать, что contactPointPtr не содержит напрямую свойства JavaScript-объектов; это низкоуровневый объект Bullet Physics, и для работы с ним требуется использование методов Ammo.js, таких как Ammo.wrapPointer.

Регистрация коллбэка

Для корректной работы onContactDestroyed необходимо использовать механизм обратных вызовов через интерфейс btDispatcher. Пример регистрации:

const dispatcher = physicsWorld.getDispatcher();
dispatcher.setContactDestroyedCallback(function(contactPointPtr, userData) {
    const contact = Ammo.wrapPointer(contactPointPtr, Ammo.btManifoldPoint);
    const body0 = contact.getBody0();
    const body1 = contact.getBody1();

    console.log("Контакт разрушен между:", body0, body1);
});

Здесь physicsWorld — экземпляр btDiscreteDynamicsWorld. Метод setContactDestroyedCallback позволяет назначить глобальную функцию для всех контактов, которые будут уничтожены.

Применение для управления ресурсами

Часто разрушение контакта используется для освобождения или обновления связанных объектов. Например, если объекты создаются динамически при столкновении (например, частицы, звуковые эффекты), необходимо своевременно удалять их:

dispatcher.setContactDestroyedCallback(function(contactPointPtr, userData) {
    const contact = Ammo.wrapPointer(contactPointPtr, Ammo.btManifoldPoint);
    const particleId = contact.getUserPersistentData(); // идентификатор связанных ресурсов
    if (particleId) {
        particleSystem.removeParticle(particleId);
    }
});

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

Управление памятью и безопасное использование

Ammo.js работает через WebAssembly и использует ручное управление памятью. Любой объект, созданный через Ammo.wrapPointer или new Ammo.*, должен быть освобожден после использования:

const contact = Ammo.wrapPointer(contactPointPtr, Ammo.btManifoldPoint);

// работа с contact

Ammo.destroy(contact); // освобождение памяти

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

Особенности взаимодействия с динамическими и статическими телами

  • Динамические тела: для тел с массой коллбэк вызывается при завершении физического контакта, например, после отскока или разрушения объекта.
  • Статические тела: разрушение контакта может произойти при перемещении статических объектов вручную через метод setWorldTransform. Важно отслеживать такие события, чтобы корректно обновлять логику игры.

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

Примеры расширенного использования

  1. Визуализация разрушений: коллбэк может инициировать эффекты, например, искры или трещины, на месте разрушенного контакта.
  2. Логирование взаимодействий: хранение статистики столкновений для анализа физической симуляции.
  3. Синхронизация с сетевыми событиями: уведомление клиента о разрушении контакта между объектами для согласованного состояния в многопользовательских играх.

Практические советы

  • Всегда проверять существование тел перед доступом к ним через getBody0 и getBody1.
  • Не хранить прямые ссылки на объекты Bullet после их удаления. Использовать идентификаторы или копии данных.
  • Комбинировать onContactDestroyed с onContactAdded для полной обработки жизненного цикла коллизий.
  • Учитывать производительность: коллбэк вызывается для каждого разрушенного контакта, что может быть сотни раз за кадр при сложной сцене.

Заключение

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