Реализация kinematic character controller

Kinematic character controller (KCC) в Ammo.js представляет собой компонент управления персонажем, который работает на основе кинематической модели вместо динамической. В отличие от обычных rigid body, кинематический контроллер не подчиняется полностью физическим силам, таким как гравитация или столкновения с другими объектами, а позволяет напрямую задавать положение и движение персонажа. Это особенно важно для игр, где необходимо контролировать точное перемещение и взаимодействие с окружением без эффекта «шарика, катящегося по наклонной поверхности».

KCC реализуется через комбинацию btKinematicCharacterController и вспомогательных коллизионных объектов, обычно btConvexShape, таких как капсула (btCapsuleShape). Важная особенность: контроллер сам управляет коллизиями, используя встроенный ghost object (btPairCachingGhostObject), который фиксирует столкновения с другими физическими телами, но не влияет на их физическое состояние.


Создание и настройка персонажа

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

  1. Создание формы коллизии
const capsuleHeight = 1.8;
const capsuleRadius = 0.3;
const capsuleShape = new Ammo.btCapsuleShape(capsuleRadius, capsuleHeight);
  1. Создание ghost object
const ghostObject = new Ammo.btPairCachingGhostObject();
const startTransform = new Ammo.btTransform();
startTransform.setIdentity();
startTransform.setOrigin(new Ammo.btVector3(0, capsuleHeight / 2, 0));
ghostObject.setWorldTransform(startTransform);
ghostObject.setCollisionShape(capsuleShape);
ghostObject.setCollisionFlags(Ammo.cf_kinematic_object | Ammo.cf_character_object);

Ghost object позволяет контроллеру отслеживать столкновения без воздействия на физические объекты сцены. Флаги cf_kinematic_object и cf_character_object критичны для корректной работы контроллера.

  1. Создание kinematic character controller
const stepHeight = 0.35;
const characterController = new Ammo.btKinematicCharacterController(ghostObject, capsuleShape, stepHeight);
physicsWorld.addAction(characterController);

stepHeight определяет максимальную высоту препятствия, через которое персонаж может «перешагнуть». Это важно для естественного движения по сцене с лестницами или небольшими бордюрами.


Основные методы управления

btKinematicCharacterController предоставляет набор методов для перемещения и управления состоянием персонажа:

  • setWalkDirection(btVector3): задаёт направление движения с учётом времени симуляции. Персонаж двигается плавно, обходя коллизии.
  • setVelocityForTimeInterval(btVector3, float): задаёт скорость на определённый промежуток времени. Полезно для реализации ускорений или рывков.
  • jump(): инициирует прыжок. Контроллер автоматически учитывает высоту прыжка и гравитацию.
  • onGround(): возвращает true, если персонаж находится на поверхности. Используется для ограничения возможности прыжка только с земли.
  • setMaxSlope(float): задаёт максимальный угол наклона поверхности, на которой персонаж может стоять.

Пример перемещения:

const direction = new Ammo.btVector3(1, 0, 0);
characterController.setWalkDirection(direction.op_mul(deltaTime));

Метод op_mul используется для масштабирования вектора на время кадра, чтобы движение было плавным и независимым от FPS.


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

Контроллер работает через ghost object, который накапливает все объекты, с которыми было взаимодействие. Для получения информации о коллизиях применяются методы:

const numOverlaps = ghostObject.getNumOverlappingObjects();
for (let i = 0; i < numOverlaps; i++) {
    const overlappingObject = ghostObject.getOverlappingObject(i);
    // Обработка столкновения
}

Важно понимать, что KCC не влияет на столкнувшиеся объекты физически. Для реакции объектов на столкновения необходимо отдельно управлять rigid bodies сцены.


Настройка гравитации и прыжка

Хотя KCC сам не является динамическим телом, он учитывает гравитацию через setGravity:

characterController.setGravity(new Ammo.btVector3(0, -9.8, 0));

Параметр jumpSpeed регулирует высоту прыжка:

characterController.setJumpSpeed(10);

Комбинация этих настроек позволяет создавать реалистичные движения персонажа: естественные прыжки, падения и шаги по наклонной поверхности.


Ограничения и рекомендации

  • KCC не взаимодействует с физикой объектов напрямую. Для воздействия на мир нужно использовать дополнительные rigid bodies.
  • Перемещения должны выполняться через setWalkDirection или setVelocityForTimeInterval. Прямое изменение трансформации ghost object может вызвать некорректные коллизии.
  • Высокие скорости или большие шаги по кадру могут приводить к «проскакиванию» препятствий. Рекомендуется использовать маленькие шаги и регулярное обновление физического мира.
  • Для комплексных движений (скольжение по склонам, лестницы, прыжки) следует тщательно настраивать stepHeight, maxSlope и гравитацию.

Интеграция с циклом физики

KCC требует регулярного обновления в цикле симуляции:

function updatePhysics(deltaTime) {
    // Обновление контроллера
    const walkDir = computeDirection();
    characterController.setWalkDirection(walkDir.op_mul(deltaTime));

    physicsWorld.stepSimulation(deltaTime, 10);
}

computeDirection() формирует вектор движения на основе пользовательского ввода или AI. Важно, чтобы stepSimulation выполнялся после задания направления движения для корректного взаимодействия с миром.


Применение в игровых сценариях

KCC на базе Ammo.js широко используется для:

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

Использование btKinematicCharacterController обеспечивает баланс между управляемостью персонажа и физической реалистичностью взаимодействия с окружением. Он позволяет реализовать плавные движения, прыжки, скольжение по склонам и безопасное преодоление препятствий, сохраняя при этом стабильность симуляции.