Кинематические тела (kinematic bodies) в Ammo.js представляют собой объекты, положение которых задаётся напрямую через код, а не вычисляется физическим движком. Они не подвержены действию силы тяжести, столкновений и других физических воздействий, но могут влиять на динамические объекты при столкновениях. Это делает их идеальными для платформ, лифтов, движущихся препятствий и анимационных объектов в физической сцене.
В Ammo.js кинематическое тело создаётся аналогично динамическому, но с отличием в флаге движения.
btCollisionShape). Например, для коробки:const boxShape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));
const mass = 0;
const transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 5, 0));
const motionState = new Ammo.btDefaultMotionState(transform);
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 для вращения).Для контроля взаимодействия с динамическими объектами можно использовать маски столкновений:
physicsWorld.addRigidBody(body, collisionGroup, collisionMask);
Это позволяет создавать сложные сцены, где кинематические тела влияют только на определённые объекты.