Класс Spring в Cannon-es

Класс Spring предназначен для моделирования упругих соединений между телами в физическом движке Cannon-es. Он позволяет создавать поведение пружин, тянущих два тела друг к другу с определённой жесткостью и демпфированием, что необходимо для симуляции мягких связей, подвесок, мягких тканей и других динамических систем.

Конструктор Spring

Конструктор класса имеет следующую сигнатуру:

new CANNON.Spring(bodyA, bodyB, options)

Параметры:

  • bodyA — первое тело (CANNON.Body) для соединения пружиной.

  • bodyB — второе тело (CANNON.Body) для соединения.

  • options — объект настроек пружины:

    • restLength — длина пружины в состоянии покоя (по умолчанию 1).
    • stiffness — коэффициент жёсткости пружины, определяет силу восстановления (по умолчанию 100).
    • damping — коэффициент демпфирования, ослабляющий колебания (по умолчанию 1).
    • localAnchorA — точка крепления на bodyA в локальных координатах.
    • localAnchorB — точка крепления на bodyB в локальных координатах.

Пример создания пружины:

import * as CANNON from "cannon-es";

const spring = new CANNON.Spring(bodyA, bodyB, {
  restLength: 2,
  stiffness: 50,
  damping: 5,
  localAnchorA: new CANNON.Vec3(0, 1, 0),
  localAnchorB: new CANNON.Vec3(0, -1, 0)
});

Свойства пружины

  • bodyA, bodyB — ссылки на тела, между которыми действует пружина.
  • restLength — длина, при которой сила пружины равна нулю.
  • stiffness — чем выше значение, тем сильнее пружина сопротивляется растяжению или сжатию.
  • damping — уменьшает амплитуду колебаний, особенно полезно при моделировании мягких объектов.
  • localAnchorA, localAnchorB — локальные точки крепления. Позволяют перемещать точку приложения силы относительно центра масс тела.

Метод applyForce()

Метод applyForce рассчитывает и применяет силу пружины к телам. Обычно вызывается внутри игрового цикла после интеграции шагов физики.

Синтаксис:

spring.applyForce()

Принцип работы:

  1. Вычисляется мировая позиция анкерных точек:

    worldAnchorA = bodyA.pointToWorldFrame(localAnchorA)
    worldAnchorB = bodyB.pointToWorldFrame(localAnchorB)
  2. Вычисляется вектор расстояния между точками и его длина:

    let delta = worldAnchorB.vsub(worldAnchorA)
    let currentLength = delta.length()
  3. Рассчитывается сила пружины по закону Гука:

    let forceMagnitude = -stiffness * (currentLength - restLength)
  4. Добавляется демпфирующий компонент:

    let relativeVelocity = bodyB.velocity.vsub(bodyA.velocity)
    let dampingForce = relativeVelocity.dot(delta.unit()) * damping
    forceMagnitude -= dampingForce
  5. Применение силы к телам:

    let force = delta.unit().scale(forceMagnitude)
    bodyA.applyForce(force, worldAnchorA)
    bodyB.applyForce(force.scale(-1), worldAnchorB)

Настройка локальных точек крепления

Точки крепления localAnchorA и localAnchorB позволяют смещать приложение силы от центра масс:

spring.localAnchorA.set(0, 0.5, 0)
spring.localAnchorB.set(0, -0.5, 0)

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

Регулировка жёсткости и демпфирования

  • stiffness — увеличение значения делает пружину более «твёрдой», уменьшает растяжение, но может приводить к нестабильности при больших шаговых интеграциях.
  • damping — контролирует затухание колебаний. Высокие значения быстро гасят вибрации, низкие — позволяют пружине свободно колебаться.

Применение в симуляции

Пружины удобно использовать для:

  • Мягких соединений между телами (например, цепи или подвески).
  • Имитации упругих поверхностей.
  • Создания динамических сеток из тел, связанных пружинами.
  • Реализации демпфированных суставов в робототехнике и играх.

Пример использования в игровом цикле:

world.addEventListener("postStep", function () {
  spring.applyForce()
});

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

Важные нюансы

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

Расширенные возможности

Можно создавать массивы пружин для моделирования сеток или мягких тел, где каждая пружина соединяет соседние тела. Использование applyForce() для всех пружин после каждого шага физики позволяет создать реалистичную эластичную структуру с эффектом растяжения и сжатия.