Применение импульса: applyImpulse

Импульс в физике — это мгновенное изменение количества движения тела. В контексте движка Cannon.js импульс используется для резкого изменения линейной и угловой скорости тела без непосредственного задания новой скорости вручную.

В отличие от постоянной силы (applyForce), которая действует в течение временного шага симуляции, импульс применяется однократно и немедленно изменяет состояние объекта. Это особенно важно при моделировании:

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

Математически импульс определяется как:

[ J = F t]

где:

  • J — импульс,
  • F — сила,
  • Δt — интервал времени действия силы.

В физическом движке импульс сразу изменяет скорость тела:

[ v = v + ]

где m — масса тела.


Метод applyImpulse в Cannon.js

У каждого динамического тела (CANNON.Body) доступен метод:

body.applyImpulse(impulse, worldPoint);

Параметры

  • impulse — объект CANNON.Vec3, вектор импульса.
  • worldPoint — точка приложения импульса в мировых координатах.

Импульс задаётся в ньютон-секундах (N·s), а точка приложения определяет, будет ли тело только двигаться или ещё и вращаться.


Применение импульса к центру масс

Если импульс приложен строго к центру масс, тело изменяет только линейную скорость без вращения.

const impulse = new CANNON.Vec3(10, 0, 0);
body.applyImpulse(impulse, body.position);

В этом случае:

  • тело начнёт двигаться вдоль оси X,
  • угловая скорость останется неизменной.

Такой подход используется при:

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

Импульс вне центра масс: создание вращения

Если точка приложения не совпадает с центром масс, возникает крутящий момент.

const impulse = new CANNON.Vec3(0, 0, 20);
const contactPoint = new CANNON.Vec3(
    body.position.x,
    body.position.y + 1,
    body.position.z
);

body.applyImpulse(impulse, contactPoint);

Результат:

  • тело начнёт двигаться,
  • одновременно появится вращение.

Вращение вычисляется через векторное произведение:

[ = r J]

где:

  • r — вектор от центра масс до точки приложения,
  • J — импульс.

Чем дальше точка приложения от центра, тем сильнее вращение.


Импульс и масса тела

Масса напрямую влияет на изменение скорости:

[ v = ]

  • Маленькая масса → сильное изменение скорости.
  • Большая масса → слабое изменение скорости.

Пример:

const lightBody = new CANNON.Body({ mass: 1 });
const heavyBody = new CANNON.Body({ mass: 100 });

const impulse = new CANNON.Vec3(50, 0, 0);

lightBody.applyImpulse(impulse, lightBody.position);
heavyBody.applyImpulse(impulse, heavyBody.position);

Лёгкое тело резко ускорится, тяжёлое — едва заметно.


Разница между applyImpulse и applyForce

Характеристика applyImpulse applyForce
Временная природа Мгновенно В течение шага
Изменение скорости Немедленно Постепенно
Подходит для Ударов, выстрелов Двигателей, тяги

applyForce аккумулируется и интегрируется в течение шага симуляции. applyImpulse изменяет скорость немедленно, минуя интеграцию силы во времени.


Локальные и мировые координаты

Метод applyImpulse принимает точку в мировых координатах. Если требуется задать импульс в локальной системе координат тела, необходимо выполнить преобразование:

const localPoint = new CANNON.Vec3(0, 1, 0);
const worldPoint = body.pointToWorldFrame(localPoint);

body.applyImpulse(new CANNON.Vec3(0, 0, 10), worldPoint);

Без правильного преобразования импульс будет приложен в неверной точке, что приведёт к некорректному вращению.


Импульс и столкновения

Во время столкновения движок автоматически рассчитывает контактные импульсы. Однако возможно программное вмешательство, например, при реализации:

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

Пример усиленного отскока:

world.addEventListener("postStep", () => {
    if (collisionDetected) {
        const boost = new CANNON.Vec3(0, 20, 0);
        body.applyImpulse(boost, body.position);
    }
});

Импульс изменяет уже вычисленную скоростью после стандартной обработки контакта.


Применение импульса для прыжка

Импульс — оптимальный способ реализовать прыжок персонажа:

function jump() {
    const jumpImpulse = new CANNON.Vec3(0, 5 * body.mass, 0);
    body.applyImpulse(jumpImpulse, body.position);
}

Умножение на массу обеспечивает одинаковую высоту прыжка для тел разной массы.


Импульс и угловая скорость

При приложении вне центра масс изменяется свойство:

body.angularVelocity

Для контроля вращения после импульса может потребоваться ограничение:

body.angularDamping = 0.5;

Высокое демпфирование снижает скорость вращения со временем.


Импульс и спящие тела

Если тело находится в состоянии сна (sleeping), вызов applyImpulse автоматически пробуждает его. Это позволяет корректно взаимодействовать с неподвижными объектами.

body.sleep(); 
body.applyImpulse(new CANNON.Vec3(10, 0, 0), body.position);

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


Практический пример: выстрел с отдачей

function shoot() {
    const shootDirection = new CANNON.Vec3(0, 0, -1);
    const power = 50;

    const impulse = shootDirection.scale(power);
    projectile.applyImpulse(impulse, projectile.position);

    // отдача
    const recoil = shootDirection.scale(-power * 0.2);
    playerBody.applyImpulse(recoil, playerBody.position);
}

Здесь:

  • снаряд получает импульс вперёд,
  • игрок — обратный импульс меньшей величины.

Так достигается реалистичная физическая отдача.


Масштаб импульса и стабильность симуляции

Слишком большие импульсы могут привести к:

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

Рекомендуется:

  • увеличивать частоту обновления world.step,
  • корректировать массу,
  • использовать ограничение скорости,
  • применять continuous collision detection при необходимости.

Взаимодействие с ограничениями (Constraints)

При наличии ограничений (HingeConstraint, PointToPointConstraint) импульс может приводить к:

  • напряжению в соединениях,
  • разрыву слабых связей,
  • резкому вращению.

Импульс действует до расчёта ограничений на текущем шаге, поэтому итоговое движение корректируется системой ограничений.


Расширенный пример: взрыв

function explode(center, radius, strength) {
    world.bodies.forEach(body => {
        const distance = body.position.distanceTo(center);

        if (distance < radius) {
            const direction = body.position.vsub(center);
            direction.normalize();

            const force = strength * (1 - distance / radius);
            const impulse = direction.scale(force);

            body.applyImpulse(impulse, body.position);
        }
    });
}

Особенности:

  • сила уменьшается с расстоянием,
  • импульс направлен радиально,
  • создаётся реалистичная ударная волна.

Контроль скорости после импульса

После применения импульса скорость можно ограничить:

const maxSpeed = 20;

if (body.velocity.length() > maxSpeed) {
    body.velocity.scale(
        maxSpeed / body.velocity.length(),
        body.velocity
    );
}

Это предотвращает чрезмерное ускорение.


Внутренний механизм изменения состояния

Внутри движка импульс:

  1. Изменяет линейную скорость:

    velocity += impulse * invMass
  2. Вычисляет момент:

    torque = r x impulse
  3. Изменяет угловую скорость через инерционный тензор.

Таким образом, applyImpulse — это прямое вмешательство в кинематическое состояние тела, минуя накопление сил.


Когда применять импульс

Импульс предпочтителен при моделировании:

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

Для длительного воздействия (двигатели, тяга, ветер) следует использовать силы.


Метод applyImpulse в Cannon.js является фундаментальным инструментом для создания реалистичных мгновенных взаимодействий в физической симуляции. Корректное понимание точки приложения, массы, инерции и масштаба импульса позволяет строить устойчивые и предсказуемые физические модели любой сложности.