Изменения API относительно оригинального Cannon.js

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

Инициализация мира

В оригинальной версии Cannon.js создание физического мира выглядело так:

const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 10;

В обновлённой версии API появились следующие изменения:

  • Конструктор World теперь принимает объект с настройками:
const world = new CANNON.World({
    gravity: new CANNON.Vec3(0, -9.82, 0),
    broadphase: new CANNON.SAPBroadphase(),
    solverIterations: 10,
});
  • broadphase рекомендуется использовать SAPBroadphase для увеличения производительности при множественных объектах. NaiveBroadphase остаётся для совместимости, но менее эффективен.

  • Параметр solver.iterations заменён на solverIterations при инициализации. Доступ к solver теперь через world.solver возможен для расширенной настройки.

Работа с телами

Создание тел (Body) и форм (Shape) претерпело структурные изменения:

const sphereShape = new CANNON.Sphere(1);
const sphereBody = new CANNON.Body({
    mass: 5,
    position: new CANNON.Vec3(0, 10, 0),
    shape: sphereShape,
});
world.addBody(sphereBody);

Ключевые изменения:

  • Конструктор Body принимает объект с параметрами (mass, position, shape, velocity, angularVelocity), вместо последовательного задания свойств после создания.
  • Свойство position теперь задаётся непосредственно через объект Vec3.
  • Методы addShape остаются для добавления дополнительных форм к телу, но инициализация нескольких форм через конструктор теперь поддерживается через массив shapes.
const boxShape = new CANNON.Box(new CANNON.Vec3(1,1,1));
const compoundBody = new CANNON.Body({
    mass: 10,
    shapes: [sphereShape, boxShape],
    positions: [new CANNON.Vec3(0,0,0), new CANNON.Vec3(1,1,1)],
});

Материалы и контактные свойства

Система материалов получила улучшения для работы с трением и упругостью:

const groundMaterial = new CANNON.Material({ friction: 0.5, restitution: 0.7 });
const ballMaterial = new CANNON.Material({ friction: 0.3, restitution: 0.9 });

const contactMaterial = new CANNON.ContactMaterial(
    groundMaterial,
    ballMaterial,
    { friction: 0.4, restitution: 0.8 }
);
world.addContactMaterial(contactMaterial);

Изменения:

  • Конструктор Material теперь принимает объект с настройками friction и restitution.
  • ContactMaterial создаётся явно для пары материалов, а параметры трения и упругости задаются через объект.
  • Методы addMaterial остались, но чаще используется прямое связывание через ContactMaterial.

Ограничения и соединения (Constraints)

API для ограничений претерпело унификацию:

  • Ранее применялся набор классов: DistanceConstraint, PointToPointConstraint, HingeConstraint.
  • Теперь их использование стандартизировано через объект конфигурации при создании:
const hinge = new CANNON.HingeConstraint(bodyA, bodyB, {
    pivotA: new CANNON.Vec3(1,0,0),
    axisA: new CANNON.Vec3(0,1,0),
    pivotB: new CANNON.Vec3(-1,0,0),
    axisB: new CANNON.Vec3(0,1,0),
    maxForce: 1e6
});
world.addConstraint(hinge);

Изменения:

  • Параметры ограничения передаются как объект, а не через отдельные методы.
  • maxForce стал обязательным для большинства динамических соединений.
  • Методы enableMotor и setMotorSpeed сохранились, но требуют корректного указания pivot и axis через векторы.

Коллизии и события

События столкновений теперь централизованы через world и тело (Body):

sphereBody.addEventListener('collide', function(event){
    console.log('Collision with', event.body);
});

world.addEventListener('postStep', function(){
    console.log('World step completed');
});

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

  • Событие collide передаёт объект события с contact и body, что упрощает доступ к деталям столкновения.
  • postStep и preStep позволяют вставлять обработку логики до или после физического шага.
  • Старая система beginContact / endContact более не используется.

Обновление мира (Simulation Step)

Метод step изменился:

const fixedTimeStep = 1.0 / 60.0;
const maxSubSteps = 3;

world.step(fixedTimeStep, deltaTime, maxSubSteps);
  • deltaTime — реальное прошедшее время между кадрами, maxSubSteps — максимальное количество внутренних шагов для компенсации проседаний FPS.
  • Ранее step(dt) просто принимал единый параметр времени, теперь рекомендовано использовать три аргумента для стабильной симуляции.

Векторные и кватернионные операции

  • Vec3 и Quaternion получили расширенные методы copy, clone, normalize, vmult, что упрощает работу с преобразованиями.
  • Старые операции через v1.vadd(v2) остаются, но часто заменяются на новые цепочки методов для читаемости кода.
const force = new CANNON.Vec3(10,0,0);
body.applyForce(force, body.position.clone());

Работа с массой и инерцией

  • Свойства mass, invMass, inertia, invInertia теперь доступны сразу после инициализации тела.
  • Метод updateMassProperties() следует вызывать после изменения mass или shapes, чтобы пересчитать инерцию.

Поддержка типов данных

  • Современная версия поддерживает TypeScript, что требует строгой типизации при создании тел, форм, материалов и ограничений.
  • Использование интерфейсов и объектов конфигурации снижает риск ошибок и упрощает автодополнение в редакторах.

Итоговые ключевые моменты изменений API

  • Инициализация через объекты конфигурации вместо последовательного задания свойств.
  • Поддержка массивов для compound-объектов (shapes, positions).
  • Материалы и контакты через объекты с явными свойствами.
  • Ограничения создаются через объекты, с явным указанием pivot, axis и maxForce.
  • Централизованные события через addEventListener для тел и мира.
  • Метод step теперь принимает три аргумента для стабильной симуляции.
  • Расширенные методы Vec3 и Quaternion, упрощение операций.
  • Полная совместимость с TypeScript и строгой типизацией.

Эти изменения делают API более согласованным, предсказуемым и удобным для интеграции в современные JavaScript-проекты с физикой реального времени.