В физическом движке Cannon.js гравитация реализуется
как постоянное ускорение, действующее на динамические тела в пределах
физического мира. Гравитация не задаётся для объекта напрямую — она
является свойством экземпляра CANNON.World и влияет на все
тела, добавленные в этот мир.
В основе расчётов лежит классическая формула движения:
[ F = m g]
где:
m — масса тела,g — вектор гравитации.Если масса равна нулю, тело считается статическим и гравитация на него не действует.
Гравитация задаётся через вектор CANNON.Vec3:
const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);
Значения по осям:
X — горизонтальное направление вправо/влево,Y — вертикаль,Z — глубина сцены.Чаще всего гравитация направляется вдоль отрицательной оси
Y.
world.gravity.set(5, -9.82, 0);
В этом случае тела будут падать под углом.
Несмотря на то, что гравитация задаётся для всего мира, поведение конкретного тела определяется следующими параметрами:
mass)const body = new CANNON.Body({
mass: 5
});
mass > 0 — тело динамическое, подвержено
гравитации.mass = 0 — тело статическое, не подвержено
гравитации.type)В Cannon.js существуют три типа тел:
CANNON.Body.DYNAMICCANNON.Body.STATICCANNON.Body.KINEMATICПример:
body.type = CANNON.Body.KINEMATIC;
Kinematic-тела не реагируют на силы, включая гравитацию.
В Cannon.js отсутствует встроенный флаг вида
useGravity = false, однако существует несколько способов
добиться аналогичного эффекта.
Гравитационная сила добавляется каждый шаг симуляции. Её можно компенсировать:
world.addEventListener('postStep', function () {
body.force.y += body.mass * 9.82;
});
Таким образом создаётся противоположная сила.
Высокое значение linearDamping снижает влияние
гравитации:
body.linearDamping = 0.9;
Метод не отключает гравитацию полностью, но уменьшает ускорение.
const body = new CANNON.Body({
mass: 0
});
body.type = CANNON.Body.KINEMATIC;
Такое тело управляется вручную через изменение позиции или скорости.
Для реализации индивидуальной гравитации используется метод
applyForce.
const customGravity = new CANNON.Vec3(0, -20, 0);
world.addEventListener('postStep', function () {
body.applyForce(
new CANNON.Vec3(
customGravity.x * body.mass,
customGravity.y * body.mass,
customGravity.z * body.mass
),
body.position
);
});
Таким образом создаётся альтернативная гравитация для конкретного объекта.
Cannon.js не содержит встроенной поддержки гравитации от нескольких тел, однако её можно реализовать вручную, используя закон всемирного тяготения:
[ F = G ]
Пример реализации:
const G = 6.67;
function applyGravityBetween(body1, body2) {
const direction = new CANNON.Vec3();
body2.position.vsub(body1.position, direction);
const distance = direction.length();
direction.normalize();
const forceMagnitude = G * body1.mass * body2.mass / (distance * distance);
direction.scale(forceMagnitude, direction);
body1.applyForce(direction, body1.position);
direction.negate(direction);
body2.applyForce(direction, body2.position);
}
Функция вызывается в каждом шаге симуляции.
Расчёт гравитации выполняется при вызове:
world.step(timeStep);
Во время шага:
Стабильность гравитации зависит от величины timeStep.
Рекомендуемое значение:
const timeStep = 1 / 60;
Слишком большой шаг приводит к неточностям и «рывкам» движения.
В Cannon.js реализован механизм сна (sleeping). Если
тело засыпает, гравитация на него не действует до пробуждения.
body.allowSleep = true;
body.sleepSpeedLimit = 0.1;
body.sleepTimeLimit = 1;
После пробуждения тело снова начинает реагировать на гравитацию.
Если тело участвует в ограничениях (например,
DistanceConstraint), гравитация может создавать
дополнительные силы натяжения.
Пример:
const constraint = new CANNON.DistanceConstraint(bodyA, bodyB);
world.addConstraint(constraint);
Гравитация будет воздействовать на оба тела, а ограничение — компенсировать изменение расстояния между ними.
1. Масса равна нулю. Тело не падает, потому что считается статическим.
2. Отсутствие вызова world.step(). Без
шага симуляции гравитация не применяется.
3. Неверная ось направления. Если используется другая система координат (например, в Three.js), направление гравитации может быть перепутано.
4. Слишком большой timeStep. Приводит к
нестабильной физике.
const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);
const shape = new CANNON.Sphere(1);
const body = new CANNON.Body({
mass: 2,
shape: shape
});
world.addBody(body);
const customGravity = new CANNON.Vec3(0, -30, 0);
world.addEventListener('postStep', function () {
const force = customGravity.scale(body.mass);
body.applyForce(force, body.position);
});
В результате тело испытывает суммарное ускорение, складывающееся из глобальной и дополнительной гравитации.
Гравитация в Cannon.js — это не «падение», а постоянная сила, добавляемая к списку сил каждого динамического тела. Итоговое движение формируется суммой:
Индивидуальная гравитация достигается не изменением настроек движка, а управлением силами на уровне конкретного тела.