Контроллер персонажа на основе ghost-объекта

Основы ghost-объектов

В библиотеке Ammo.js, ghost-объект представляет собой особый тип физического объекта, который не участвует в динамическом взаимодействии с миром напрямую. Он не испытывает силы гравитации и не сталкивается с другими объектами с физическим отталкиванием. Ghost-объекты чаще всего используются для:

  • детекции пересечений (collision detection),
  • создания триггерных зон,
  • реализации персонажей, где движение контролируется напрямую, а не физикой.

Ghost-объект создается с помощью btPairCachingGhostObject. Он может иметь коллизионную форму, такую как btCapsuleShape или btBoxShape. Например, для персонажа часто используют капсулу:

const ghostShape = new Ammo.btCapsuleShape(radius, height);
const ghostObject = new Ammo.btPairCachingGhostObject();
ghostObject.setCollisionShape(ghostShape);
ghostObject.setCollisionFlags(Ammo.btCollisionObject.CF_CHARACTER_OBJECT);

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


Настройка коллизий и масок

Ghost-объект должен быть правильно настроен для взаимодействия с другими объектами сцены. В Ammo.js это делается через маски коллизий:

const collisionGroup = 2; // группа персонажей
const collisionMask = 1 | 4; // взаимодействует с мирами и объектами, но игнорирует триггеры
dynamicsWorld.addCollisionObject(ghostObject, collisionGroup, collisionMask);

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


Реализация движения персонажа

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

  1. Вычисление желаемого смещения – на основе ввода пользователя или логики AI.
  2. Проверка столкновений – с помощью ghost-объекта и метода convexSweepTest или анализа пересечений с помощью getOverlappingPairs().
  3. Применение смещения – с учетом обнаруженных препятствий.

Пример базового смещения по оси X/Z:

function moveCharacter(ghostObject, displacement, world) {
    const transform = ghostObject.getWorldTransform();
    const origin = transform.getOrigin();
    const newOrigin = new Ammo.btVector3(
        origin.x() + displacement.x,
        origin.y() + displacement.y,
        origin.z() + displacement.z
    );

    transform.setOrigin(newOrigin);
    ghostObject.setWorldTransform(transform);
}

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

Ghost-объект автоматически хранит список объектов, с которыми он пересекается, через методы:

const overlappingObjects = ghostObject.getOverlappingPairs();
for (let i = 0; i < overlappingObjects.size(); i++) {
    const obj = overlappingObjects.at(i);
    // обработка события пересечения
}

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


Управление прыжками и гравитацией

Хотя ghost-объект не подчиняется физике напрямую, для имитации прыжка или падения можно использовать вспомогательные параметры:

  • вертикальная скорость verticalVelocity,
  • гравитация gravity,
  • проверка контакта с поверхностью через getOverlappingPairs().

Пример применения вертикальной скорости:

if (isOnGround) {
    verticalVelocity = jumpSpeed;
} else {
    verticalVelocity -= gravity * deltaTime;
}

moveCharacter(ghostObject, { x: 0, y: verticalVelocity * deltaTime, z: 0 }, world);

isOnGround определяется через проверку пересечений с поверхностями, которые считаются землей.


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

Для корректной работы ghost-объекта в Ammo.js он должен быть добавлен в мир с динамическим обновлением:

dynamicsWorld.addCollisionObject(ghostObject,
                                 collisionGroup,
                                 collisionMask);

Для каждого кадра необходимо:

  1. Обновлять желаемое смещение персонажа.
  2. Выполнять проверку столкновений.
  3. Применять изменения позиции ghost-объекта.
  4. Синхронизировать визуальное представление с transform ghost-объекта.

Расширенные техники

  • Скользящие движения (sliding) – при обнаружении препятствия смещение проецируется на плоскость, перпендикулярную нормали столкновения, что позволяет персонажу “скользить” вдоль стен.
  • Плавный спуск с платформ (step-up/step-down) – проверка высоты шага и корректировка позиции по вертикали для естественного движения по лестницам или порогам.
  • Интеграция с ragdoll или rigid body объектами – ghost-объект может детектировать столкновения с физическими объектами и триггерить события, но при этом не подчиняться их силам напрямую.

Практические советы

  • Размер капсулы должен соответствовать пропорциям персонажа. Слишком маленькая форма может “залипать” в стенах, слишком большая – препятствовать проходу через двери.
  • Использовать convexSweepTest при быстром перемещении персонажа, чтобы избежать прохождения сквозь тонкие объекты.
  • Обновлять позиции визуального меша после каждого изменения transform ghost-объекта, чтобы избежать рассинхронизации с физическим миром.
  • Комбинировать ghost-объекты с raycast для точного определения земли и падений, особенно при движении по неровной поверхности.

Ghost-объект в Ammo.js обеспечивает оптимальную основу для персонажного контроллера: точное управление, проверку столкновений и гибкость при взаимодействии с окружением, без необходимости симулировать полную физику персонажа.