Cannon.js — это физический движок для JavaScript, обеспечивающий
реалистичное моделирование тел в 3D-пространстве. Он поддерживает
твердотельную динамику, коллизии, силы, трение и инерцию. Каждое тело в
сцене представлено объектом типа Body, который имеет массу,
форму (Shape), положение (position) и
ориентацию (quaternion). Для управления симуляцией
используется объект World, отвечающий за интеграцию законов
движения и обработку столкновений.
const world = new CANNON.World();
world.gravity.set(0, -9.82, 0); // Земная гравитация
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 10;
Каждое физическое тело состоит из массы,
формы и позиции. Формы
(Shape) определяют коллизионные границы: Box,
Sphere, Cylinder, Plane,
ConvexPolyhedron и другие.
const shape = new CANNON.Sphere(1); // Сфера радиусом 1
const body = new CANNON.Body({
mass: 5,
shape: shape,
position: new CANNON.Vec3(0, 10, 0)
});
world.addBody(body);
Важно помнить, что форма тела не всегда совпадает с визуальным представлением. Для синхронизации с графикой необходимо отдельно обновлять трехмерный объект, например, в Three.js.
Cannon.js обновляет симуляцию с помощью метода
world.step(timeStep), где timeStep задаёт
интервал времени для расчёта физических взаимодействий.
const timeStep = 1/60; // 60 FPS
function updatePhysics() {
world.step(timeStep);
}
После вызова step необходимо обновлять позиции и
ориентации визуальных объектов:
mesh.position.copy(body.position);
mesh.quaternion.copy(body.quaternion);
При создании больших сцен с множеством объектов возникает необходимость удалять тела, которые находятся далеко от камеры или игрока, чтобы оптимизировать производительность. Основная стратегия — проверка дистанции между телом и точкой интереса и удаление при превышении порогового значения.
function distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
const dz = a.z - b.z;
return Math.sqrt(dx*dx + dy*dy + dz*dz);
}
const removalDistance = 50;
function removeDistantBodies(referencePoint) {
for (let i = world.bodies.length - 1; i >= 0; i--) {
const body = world.bodies[i];
if (distance(body.position, referencePoint) > removalDistance) {
world.removeBody(body);
}
}
}
Использование цикла в обратном порядке предотвращает
пропуск элементов при удалении из массива world.bodies.
function removeDistantBodiesWithMeshes(referencePoint) {
for (let i = world.bodies.length - 1; i >= 0; i--) {
const body = world.bodies[i];
if (distance(body.position, referencePoint) > removalDistance) {
scene.remove(body.mesh); // удаление визуала
world.removeBody(body);
}
}
}
Для сцен с тысячами тел критически важно минимизировать накладные расходы на цикл проверки и удаление:
Удаление тел влияет на симуляцию:
Constraint),
необходимо также удалять связанные ограничения.if (body.constraint) {
world.removeConstraint(body.constraint);
}
world.removeBody(body);
Эти подходы позволяют поддерживать высокую производительность Cannon.js даже в сложных сценах с тысячами объектов, сохраняя точность физической симуляции и согласованность визуального представления.