Пошаговая симуляция для отладки

Пошаговая симуляция (step-by-step simulation) — это механизм, позволяющий контролировать процесс вычисления физики в небольших, дискретных интервалах времени. В Cannon.js этот подход критически важен для отладки сложных сцен, где объекты взаимодействуют через столкновения, трение и силы.

Базовая концепция заключается в том, что мир (World) обновляется методом step, который принимает фиксированный временной шаг и количество итераций для интеграции. Это позволяет получить предсказуемое поведение объектов, независимо от частоты кадров визуализации.

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

const timeStep = 1 / 60; // фиксированный шаг

Метод world.step()

Метод world.step(fixedTimeStep, deltaTime, maxSubSteps) выполняет интеграцию физических законов:

  • fixedTimeStep — фиксированный временной шаг симуляции. Обычно используют 1/60.
  • deltaTime — фактическое прошедшее время между кадрами. Позволяет компенсировать разницу между рендерингом и симуляцией.
  • maxSubSteps — максимальное количество подшагов, выполняемых для компенсации задержек.

Пример пошагового обновления:

function update(deltaTime) {
    world.step(timeStep, deltaTime, 10);

    // Обновление объектов на сцене
    objects.forEach(obj => {
        obj.mesh.position.copy(obj.body.position);
        obj.mesh.quaternion.copy(obj.body.quaternion);
    });
}

Ключевое преимущество пошаговой симуляции — детерминированность. Даже при изменении частоты кадров объекты будут вести себя одинаково, если используется одинаковый fixedTimeStep.


Отладка столкновений и сил

Для анализа поведения объектов часто важно видеть их траектории, силы и реакции на столкновения. Cannon.js предоставляет доступ к коллизиям через события:

body.addEventListener("collide", (event) => {
    const contact = event.contact;
    console.log("Сталкновение с объектом:", event.body.id);
    console.log("Контактная точка:", contact.rj);
    console.log("Нормаль:", contact.ni);
});

События collide позволяют пошагово отслеживать изменения, что облегчает корректировку массы, трения и упругости объектов.


Использование субшагов для точной симуляции

Когда симуляция нестабильна при больших временных шагах, можно увеличить количество подшагов (maxSubSteps). Каждый подшаг выполняет отдельный цикл интеграции, уменьшая вероятность «проваливания» объектов сквозь друг друга.

Пример:

const fixedTimeStep = 1/120; // более точный шаг
const maxSubSteps = 5;

world.step(fixedTimeStep, deltaTime, maxSubSteps);

Такой подход особенно полезен для:

  • Быстрых объектов (пули, мячики)
  • Сложных столкновений с острыми углами
  • Сцен с большим количеством динамических тел

Визуализация для пошаговой отладки

Для анализа поведения тел полезно создавать вспомогательные визуальные элементы:

  • Траектории движения: линии, соединяющие позиции тела в разных шагах.
  • Векторы сил: стрелки, показывающие направление и величину приложенных сил.
  • Контактные точки: небольшие сферы или маркеры в местах столкновений.

Пример добавления траектории:

const trajectoryMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
const trajectoryGeometry = new THREE.BufferGeometry().setFromPoints([]);
const trajectoryLine = new THREE.Line(trajectoryGeometry, trajectoryMaterial);

scene.add(trajectoryLine);

function recordTrajectory(body) {
    const points = trajectoryGeometry.attributes.position.array;
    points.push(body.position.x, body.position.y, body.position.z);
    trajectoryGeometry.setFromPoints(points.map(p => new THREE.Vector3(...p)));
}

Логирование состояния мира

Для глубокого анализа полезно записывать позиции, скорости и угловые скорости всех тел на каждом шаге:

world.bodies.forEach(body => {
    console.log(`ID: ${body.id}`);
    console.log(`Позиция: ${body.position.toString()}`);
    console.log(`Скорость: ${body.velocity.toString()}`);
});

Такое логирование позволяет пошагово воспроизводить ошибки и корректировать физические параметры.


Настройка интегратора и параметров Solver

От стабильности симуляции напрямую зависят настройки solver и интегратора:

world.solver.iterations = 20; // больше итераций — точнее, медленнее
world.solver.tolerance = 0.001; // минимальное отклонение при решении контактов

Повышение числа итераций улучшает разрешение столкновений, особенно для твердых объектов и цепочек тел.


Выводы по пошаговой симуляции

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

Пошаговая симуляция — основа для контроля, оптимизации и отладки любых физических сцен в Cannon.js.