Cannon.js — это физический движок для JavaScript, предназначенный для симуляции твердых тел, столкновений и ограничений. Он предоставляет набор классов для создания динамических объектов, их физических свойств и взаимодействий. Основные компоненты включают:
Для создания пружины можно обойтись без встроенного класса
Spring, используя базовые физические принципы: силу
упругости, демпфирование и обновление тела на каждом шаге симуляции.
Пружина описывается законом Гука:
[ F = -k x]
где:
Для стабилизации колебаний добавляется демпфирование:
[ F_{} = -c v]
где:
Суммарная сила, прикладываемая к телу:
[ F_{} = F + F_{}]
Эта сила применяется к телу на каждом шаге симуляции через метод
applyForce или applyImpulse.
Для реализации пружины между телами bodyA и
bodyB нужно вычислять:
const delta = new CANNON.Vec3();
bodyB.position.vsub(bodyA.position, delta); // delta = bodyB - bodyA
const currentLength = delta.length();
const extension = currentLength - restLength; // restLength — длина пружины в покое
const forceDirection = delta.unit(); // нормализованный вектор
const relativeVelocity = new CANNON.Vec3();
bodyB.velocity.vsub(bodyA.velocity, relativeVelocity);
const dampingForce = relativeVelocity.dot(forceDirection) * damping; // c * v
const springForce = -springConstant * extension - dampingForce;
const force = forceDirection.scale(springForce);
bodyA.applyForce(force);
bodyB.applyForce(force.negate());
Эта процедура повторяется на каждом шаге симуляции. Для интеграции с
Cannon.js используется событие postStep или обычный вызов
внутри основного цикла обновления мира:
world.addEventListener('postStep', function() {
applySpring(bodyA, bodyB, restLength, springConstant, damping);
});
Если пружина закреплена к фиксированной точке (anchor),
алгоритм упрощается:
const delta = new CANNON.Vec3();
body.position.vsub(anchor, delta);
const extension = delta.length() - restLength;
const forceDirection = delta.unit();
const dampingForce = body.velocity.dot(forceDirection) * damping;
const springForce = -springConstant * extension - dampingForce;
const force = forceDirection.scale(springForce);
body.applyForce(force);
Фиксированная точка может быть представлена как
CANNON.Vec3, и тело реагирует на силу точно так же, как
если бы это была пружина между двумя динамическими телами.
Коэффициент жесткости (springConstant, k):
Демпфирование (damping, c):
Длина покоя (restLength):
Использование описанной реализации позволяет строить:
Для стабильности симуляции рекомендуется использовать небольшие шаги
времени (dt) и корректировать коэффициенты демпфирования в
зависимости от массы тел:
[ c ]
где (m) — масса тела.
applySpringfunction applySpring(bodyA, bodyB, restLength, k, damping) {
const delta = new CANNON.Vec3();
bodyB.position.vsub(bodyA.position, delta);
const currentLength = delta.length();
const extension = currentLength - restLength;
const forceDirection = delta.unit();
const relativeVelocity = new CANNON.Vec3();
bodyB.velocity.vsub(bodyA.velocity, relativeVelocity);
const dampingForce = relativeVelocity.dot(forceDirection) * damping;
const springForce = -k * extension - dampingForce;
const force = forceDirection.scale(springForce);
bodyA.applyForce(force);
bodyB.applyForce(force.negate());
}
Эта функция позволяет гибко настраивать пружины, объединять их в
сложные конструкции и использовать как основу для создания динамических
симуляций без встроенного класса Spring Cannon.js.