Гравитация отдельного тела

В физическом движке 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);

В этом случае тела будут падать под углом.


Влияние гравитации на отдельное тело

Несмотря на то, что гравитация задаётся для всего мира, поведение конкретного тела определяется следующими параметрами:

1. Масса (mass)

const body = new CANNON.Body({
    mass: 5
});
  • mass > 0 — тело динамическое, подвержено гравитации.
  • mass = 0 — тело статическое, не подвержено гравитации.

2. Тип тела (type)

В Cannon.js существуют три типа тел:

  • CANNON.Body.DYNAMIC
  • CANNON.Body.STATIC
  • CANNON.Body.KINEMATIC

Пример:

body.type = CANNON.Body.KINEMATIC;

Kinematic-тела не реагируют на силы, включая гравитацию.


Отключение гравитации для конкретного тела

В Cannon.js отсутствует встроенный флаг вида useGravity = false, однако существует несколько способов добиться аналогичного эффекта.

Способ 1: Обнуление силы гравитации вручную

Гравитационная сила добавляется каждый шаг симуляции. Её можно компенсировать:

world.addEventListener('postStep', function () {
    body.force.y += body.mass * 9.82;
});

Таким образом создаётся противоположная сила.

Способ 2: Использование линейного демпфирования

Высокое значение linearDamping снижает влияние гравитации:

body.linearDamping = 0.9;

Метод не отключает гравитацию полностью, но уменьшает ускорение.

Способ 3: Использование кинематического тела

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);

Во время шага:

  1. Вычисляются силы (включая гравитацию),
  2. Рассчитываются ускорения,
  3. Обновляются скорости,
  4. Обновляются позиции.

Стабильность гравитации зависит от величины timeStep. Рекомендуемое значение:

const timeStep = 1 / 60;

Слишком большой шаг приводит к неточностям и «рывкам» движения.


Гравитация и спящие тела

В Cannon.js реализован механизм сна (sleeping). Если тело засыпает, гравитация на него не действует до пробуждения.

body.allowSleep = true;
body.sleepSpeedLimit = 0.1;
body.sleepTimeLimit = 1;

После пробуждения тело снова начинает реагировать на гравитацию.


Гравитация в сочетании с ограничениями (Constraints)

Если тело участвует в ограничениях (например, 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 — это не «падение», а постоянная сила, добавляемая к списку сил каждого динамического тела. Итоговое движение формируется суммой:

  • гравитации,
  • внешних сил,
  • импульсов,
  • ограничений,
  • столкновений,
  • демпфирования.

Индивидуальная гравитация достигается не изменением настроек движка, а управлением силами на уровне конкретного тела.