В библиотеке Ammo.js проверка столкновений между физическими объектами может выполняться не только через глобальные коллизионные события, но и с использованием методов, ориентированных на конкретные тела. Один из таких инструментов — ContactTest, позволяющий определить, находится ли объект в контакте с другими объектами сцены, без необходимости отслеживания всех коллизий вручную через симуляцию шагов.
Ammo.ConcreteContactResultCallback.Для проверки контактов необходимо создать объект обратного вызова,
наследующийся от Ammo.ConcreteContactResultCallback. В нём
реализуется метод addSingleResult, который вызывается для
каждой точки контакта:
class MyContactCallback extends Ammo.ConcreteContactResultCallback {
constructor() {
super();
this.contacts = [];
}
addSingleResult(cp, colObj0Wrap, partId0, index0, colObj1Wrap, partId1, index1) {
// cp — информация о точке контакта
// colObj1Wrap — объект, с которым произошло столкновение
this.contacts.push({
contactPoint: cp.get_m_positionWorldOnB(),
otherBody: Ammo.castObject(colObj1Wrap.getCollisionObject(), Ammo.btRigidBody)
});
return 0; // возвращаемое значение обычно игнорируется
}
}
После создания callback выполняется проверка столкновений:
const callback = new MyContactCallback();
physicsWorld.contactTest(rigidBody, callback);
if (callback.contacts.length > 0) {
console.log('Тело столкнулось с другими объектами', callback.contacts);
}
Метод contactTest принимает два аргумента:
rigidBody — тело, для которого проверяется
контакт.callback — объект с методом
addSingleResult.Пример фильтрации по маске:
class FilteredContactCallback extends Ammo.ConcreteContactResultCallback {
constructor(filterFunc) {
super();
this.contacts = [];
this.filterFunc = filterFunc;
}
addSingleResult(cp, colObj0Wrap, partId0, index0, colObj1Wrap, partId1, index1) {
const otherBody = Ammo.castObject(colObj1Wrap.getCollisionObject(), Ammo.btRigidBody);
if (this.filterFunc(otherBody)) {
this.contacts.push(otherBody);
}
return 0;
}
}
// Проверяем столкновение только с динамическими телами
const callback = new FilteredContactCallback(body => otherBody.getCollisionFlags() & Ammo.cf_dynamicObject);
physicsWorld.contactTest(rigidBody, callback);
Метод ContactTest более эффективен, чем постоянный обход всех коллизий через симуляцию шагов, поскольку:
Для больших сцен с множеством тел рекомендуется использовать маски коллизий и grps/filters, чтобы сократить количество проверяемых контактов.
contactTest, который
проверяет объект против всех.Использование ContactTest совместно с contactPairTest
позволяет организовать гибкую систему обнаружения столкновений, где
можно одновременно проверять и конкретные пары тел, и все столкновения
одного объекта с миром.
addSingleResult получает объект
btManifoldPoint, из которого можно извлечь:
get_m_positionWorldOnB() /
get_m_positionWorldOnA())get_m_normalWorldOnB())get_m_appliedImpulse())Необходимо кастить обёртки объектов через
Ammo.castObject, чтобы работать с
btRigidBody.
Контактный callback создаётся через
new Ammo.ConcreteContactResultCallback() или через
наследование, так как прямое использование абстрактного класса
невозможно.
Контактная проверка через ContactTest позволяет в Ammo.js гибко контролировать взаимодействия объектов, извлекать информацию о столкновениях и фильтровать их по необходимости, не вмешиваясь в динамику симуляции. Такой подход особенно полезен для игровых триггеров, сенсоров и систем AI.