Добавление тела в мир и удаление

В библиотеке Ammo.js физические объекты представляются как тела (btRigidBody), которые взаимодействуют с миром через физический движок. Процесс добавления тела начинается с определения его формы, массы и начальных свойств.

Форма тела создается с помощью коллайдеров (btCollisionShape). Среди наиболее распространенных форм:

  • Куб (btBoxShape) — определяется вектором половины размеров по осям X, Y, Z.

    let halfExtents = new Ammo.btVector3(1, 1, 1);
    let boxShape = new Ammo.btBoxShape(halfExtents);
  • Сфера (btSphereShape) — задается радиусом.

  • Цилиндр, конус, капсула (btCylinderShape, btConeShape, btCapsuleShape) — для более сложных объектов.

  • Композитные формы (btCompoundShape) — позволяют объединять несколько простых форм в одно тело.

Масса и инерция. Для динамических объектов необходимо задать массу больше нуля и вычислить локальный тензор инерции:

let mass = 5;
let localInertia = new Ammo.btVector3(0, 0, 0);
boxShape.calculateLocalInertia(mass, localInertia);

Положение и ориентация тела задаются через btTransform:

let transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 10, 0)); // начальная позиция
transform.setRotation(new Ammo.btQuaternion(0, 0, 0, 1)); // ориентация

Создание тела и добавление в мир:

let motionState = new Ammo.btDefaultMotionState(transform);
let rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, boxShape, localInertia);
let body = new Ammo.btRigidBody(rbInfo);

physicsWorld.addRigidBody(body);

Ключевой момент: все динамические объекты должны иметь вычисленный локальный тензор инерции, иначе они будут вести себя как статические.


Настройка свойств тела

После создания тела можно задать дополнительные физические свойства:

  • Коэффициент трения:
body.setFriction(0.5);
  • Отскок (Restitution):
body.setRestitution(0.7);
  • Линейная и угловая подвижность:
body.setLinearFactor(new Ammo.btVector3(1, 1, 1));
body.setAngularFactor(new Ammo.btVector3(0, 1, 0)); // вращение только по оси Y
  • Активизация и деактивизация тела: тела, находящиеся в покое, могут быть временно деактивированы для оптимизации.
body.setActivationState(Ammo.DISABLE_DEACTIVATION);

Удаление тела из мира

Удаление тела из мира в Ammo.js требует нескольких шагов, чтобы избежать утечек памяти, так как библиотека использует систему ручного управления памятью.

Пошаговый процесс:

  1. Удаление тела из мира:
physicsWorld.removeRigidBody(body);
  1. Удаление состояния движения (MotionState):
let motionState = body.getMotionState();
if (motionState) {
    Ammo.destroy(motionState);
}
  1. Удаление коллайдера:
let shape = body.getCollisionShape();
Ammo.destroy(shape);
  1. Удаление самого тела:
Ammo.destroy(body);

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


Динамическое добавление и удаление тел

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

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

Пример динамического удаления по условию позиции:

if (body.getWorldTransform().getOrigin().y() < -10) {
    physicsWorld.removeRigidBody(body);
    Ammo.destroy(body.getMotionState());
    Ammo.destroy(body.getCollisionShape());
    Ammo.destroy(body);
}

Оптимизация работы с телами

  1. Использовать статические тела (mass = 0) для объектов, которые не должны двигаться. Это снижает нагрузку на физический движок.
  2. Пуллинг объектов вместо частого создания и уничтожения. Можно хранить несколько тел в массиве и повторно использовать их.
  3. Разделение на группы и маски коллизий для уменьшения числа проверок столкновений:
physicsWorld.addRigidBody(body, group, mask);
  • group — группа, к которой относится тело
  • mask — с какими группами оно может сталкиваться

Работа с комплексными формами и иерархией

btCompoundShape позволяет создавать сложные тела, комбинируя несколько коллайдеров:

let compound = new Ammo.btCompoundShape();
let childTransform = new Ammo.btTransform();
childTransform.setIdentity();
childTransform.setOrigin(new Ammo.btVector3(0, 1, 0));

compound.addChildShape(childTransform, boxShape);

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


Важные рекомендации

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

Эти правила позволяют эффективно управлять физическими объектами, обеспечивая корректную симуляцию и стабильную работу приложения.