Создание кинематических тел

Кинематические тела (kinematic bodies) в Ammo.js представляют собой объекты, положение которых задаётся напрямую через код, а не вычисляется физическим движком. Они не подвержены действию силы тяжести, столкновений и других физических воздействий, но могут влиять на динамические объекты при столкновениях. Это делает их идеальными для платформ, лифтов, движущихся препятствий и анимационных объектов в физической сцене.

В Ammo.js кинематическое тело создаётся аналогично динамическому, но с отличием в флаге движения.

Создание кинематического тела

  1. Форма коллайдера Для тела необходима форма (btCollisionShape). Например, для коробки:
const boxShape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));
  1. Массa и движение Кинематические тела имеют массу равную нулю. Для их обозначения используется:
const mass = 0;
  1. Положение и трансформация Каждое тело требует начальной трансформации:
const transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 5, 0));
const motionState = new Ammo.btDefaultMotionState(transform);
  1. Создание тела с кинематическим флагом Объект создаётся через btRigidBody:
const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, boxShape);
const body = new Ammo.btRigidBody(rbInfo);

// Установка флага кинематического объекта
body.setCollisionFlags(body.getCollisionFlags() | 2); // 2 = CF_KINEMATIC_OBJECT

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

Перемещение кинематического тела

Перемещение осуществляется через изменение трансформации напрямую:

const newTransform = new Ammo.btTransform();
newTransform.setIdentity();
newTransform.setOrigin(new Ammo.btVector3(x, y, z));
body.getMotionState().setWorldTransform(newTransform);
body.setWorldTransform(newTransform);

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

Взаимодействие с динамическими объектами

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

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

Обновление в цикле

Кинематические тела чаще всего перемещаются в игровом цикле:

function updateKinematicBody(body, deltaTime) {
    const transform = new Ammo.btTransform();
    body.getMotionState().getWorldTransform(transform);
    
    const origin = transform.getOrigin();
    origin.setX(origin.x() + deltaTime * speedX);
    origin.setY(origin.y() + deltaTime * speedY);
    origin.setZ(origin.z() + deltaTime * speedZ);
    
    transform.setOrigin(origin);
    body.getMotionState().setWorldTransform(transform);
    body.setWorldTransform(transform);
}

Такой подход позволяет плавно перемещать тело с учётом времени, сохраняя корректные столкновения с динамическими объектами.

Использование анимаций

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

  • Интерполяция между ключевыми точками (lerp для позиции, slerp для вращения).
  • Связь с внешним объектом визуализации (Three.js, Babylon.js) для отображения движения.
  • Комбинация с динамическими телами для реалистичных эффектов физики.

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

  • Кинематические тела не реагируют на силу тяжести и столкновения, поэтому для их взаимодействия с динамическими объектами необходимо обновлять трансформацию вручную.
  • Резкое перемещение тела может привести к телепортации динамических объектов, если они не успевают корректно столкнуться.
  • Для корректного столкновения с другими объектами рекомендуется обновлять трансформацию каждую физическую итерацию.

Практические применения

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

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

Для контроля взаимодействия с динамическими объектами можно использовать маски столкновений:

physicsWorld.addRigidBody(body, collisionGroup, collisionMask);
  • collisionGroup — группа, к которой принадлежит кинематическое тело.
  • collisionMask — группы, с которыми тело может сталкиваться.

Это позволяет создавать сложные сцены, где кинематические тела влияют только на определённые объекты.

Рекомендации по производительности

  • Кинематические тела дешевле в вычислении, чем динамические с массой, но частое обновление трансформации большого числа объектов может быть нагрузочным.
  • Объединение нескольких мелких кинематических объектов в один или использование простых коллайдеров уменьшает нагрузку.
  • Для гладкого движения и точных столкновений стоит синхронизировать визуализацию и физику через один и тот же временной шаг.