В Cannon.js детерминированная симуляция означает, что при одинаковых начальных условиях и одинаковых параметрах физического мира последовательность состояний системы будет одинаковой при каждом запуске. Это критически важно для многопользовательских игр, сетевых симуляций и тестирования физических систем, где требуется строгая воспроизводимость поведения объектов.
Инициализация случайных чисел Cannon.js использует генератор случайных чисел для некоторых внутренних процессов (например, при столкновениях или рассеивании импульсов). Для воспроизводимости необходимо фиксировать seed генератора. Без этого идентичная симуляция может давать разные результаты при каждом запуске.
Пошаговое интегрирование Cannon.js применяет метод Velocity Verlet или Euler integration для обновления позиции и скорости тел. Погрешности в численных методах накапливаются со временем. Чтобы симуляция была детерминированной:
fixedTimeStep.dt, зависящих от
реального времени.Пример:
const fixedTimeStep = 1 / 60; // 60 FPS
const maxSubSteps = 3;
world.step(fixedTimeStep, deltaTime, maxSubSteps);Стабильность столкновений Сложные сцены с множественными контактами могут приводить к неопределенному порядку разрешения коллизий. Для детерминированности важно:
Box,
Sphere, Plane) вместо сложных
ConvexPolyhedron, которые чувствительны к малым
погрешностям.Фиксированные свойства тел Плотность, масса, момент инерции и коэффициенты трения должны быть строго определены:
const body = new CANNON.Body({
mass: 5,
shape: new CANNON.Box(new CANNON.Vec3(1, 1, 1)),
material: new CANNON.Material({
friction: 0.3,
restitution: 0.6
})
});Инициализация мира
const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 10; // фиксированное число итераций
Установка фиксированного числа итераций решателя
solver.iterations важна, так как адаптивные итерации могут
вносить различия между симуляциями.
Фиксированный шаг времени Использование
переменной deltaTime для вычислений симуляции на основе
реального времени (performance.now() или
Date.now()) приводит к
недетерминированности, особенно при сетевой
синхронизации. Для сохранения детерминированности:
let lastTime;
function animate(time) {
const deltaTime = lastTime ? (time - lastTime) / 1000 : 0;
lastTime = time;
const fixedTimeStep = 1 / 60;
const maxSubSteps = 3;
world.step(fixedTimeStep, deltaTime, maxSubSteps);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);Состояние мира Для воспроизводимости важно уметь сохранять и восстанавливать состояние мира. Cannon.js позволяет извлечь позиции, ориентации и скорости тел:
const state = world.bodies.map(body => ({
position: body.position.clone(),
velocity: body.velocity.clone(),
quaternion: body.quaternion.clone(),
angularVelocity: body.angularVelocity.clone()
}));
Для восстановления:
world.bodies.forEach((body, index) => {
body.position.copy(state[index].position);
body.velocity.copy(state[index].velocity);
body.quaternion.copy(state[index].quaternion);
body.angularVelocity.copy(state[index].angularVelocity);
});timeStep, контроль состояния и сохранение seed генератора
для надежной синхронизации.Эти подходы позволяют создавать предсказуемую и стабильную симуляцию даже в сложных 3D-сценах с множеством динамических объектов.