Cannon.js предоставляет мощный движок физики для трёхмерных объектов
в Javascript, позволяя моделировать движение, столкновения и
динамическое взаимодействие. Для реализации управления транспортным
средством или любым подвижным объектом важно понять, как применять силы
и крутящий момент к телам (Body) и как использовать
свойства физического тела для корректного отклика на пользовательский
ввод.
Для управления объектом сначала необходимо создать его физическое тело и задать базовые параметры:
const mass = 1500; // масса в килограммах
const vehicleBody = new CANNON.Body({
mass: mass,
position: new CANNON.Vec3(0, 0.5, 0),
shape: new CANNON.Box(new CANNON.Vec3(1, 0.5, 2))
});
// Настройка динамики
vehicleBody.linearDamping = 0.2; // сопротивление линейному движению
vehicleBody.angularDamping = 0.3; // сопротивление вращению
world.addBody(vehicleBody);
Ключевой момент: linearDamping и
angularDamping определяют, насколько тело замедляется
естественным образом без приложенных сил. Для транспорта эти значения
часто выбираются малыми, чтобы движение оставалось отзывчивым, но не
слишком резким.
В Cannon.js движение создаётся за счёт применения
силы (applyForce) или
импульса (applyImpulse) к телу. Для
имитации газа и тормоза лучше использовать силу, направленную вдоль оси
движения:
const forceMagnitude = 5000; // сила ускорения
const brakeForce = -3000; // сила торможения
function applyThrottle(body, forward = true) {
const direction = forward ? 1 : -1;
const force = new CANNON.Vec3(0, 0, direction * forceMagnitude);
body.applyForce(force, body.position);
}
function applyBrake(body) {
const velocity = body.velocity.length();
if (velocity > 0) {
const brakeDirection = body.velocity.scale(-1 / velocity);
const brake = brakeDirection.scale(Math.abs(brakeForce));
body.applyForce(brake, body.position);
}
}
Важная особенность: силы необходимо применять каждый
кадр симуляции, иначе движение тела будет прерывистым. Использование
body.velocity.length() позволяет создавать плавное
торможение в зависимости от текущей скорости.
Поворот управляется изменением углового момента тела
(torque) вокруг вертикальной оси. Для имитации руля
применяют момент к телу:
const steerTorque = 200; // величина крутящего момента
function steer(body, angle) {
const torque = new CANNON.Vec3(0, angle * steerTorque, 0);
body.torque.vadd(torque, body.torque);
}
Примечание: угол рулевого управления может быть
выражен в радианах или в диапазоне -1..1, где отрицательное
значение — поворот влево, положительное — вправо.
Для реалистичного поведения транспортного средства важно комбинировать линейные и угловые силы. Один из подходов — каждый кадр вычислять и применять:
world.addEventListener('postStep', () => {
if (controls.forward) applyThrottle(vehicleBody, true);
if (controls.backward) applyThrottle(vehicleBody, false);
if (controls.brake) applyBrake(vehicleBody);
steer(vehicleBody, controls.steer); // -1..1
});
Для предотвращения чрезмерной скорости или неконтролируемого скольжения применяются ограничения:
const maxSpeed = 50; // макс. скорость в м/с
if (vehicleBody.velocity.length() > maxSpeed) {
vehicleBody.velocity.scale(maxSpeed / vehicleBody.velocity.length(), vehicleBody.velocity);
}
// Снижение бокового скольжения
const lateralVelocity = new CANNON.Vec3(vehicleBody.velocity.x, 0, vehicleBody.velocity.z);
lateralVelocity.scale(0.9, lateralVelocity);
vehicleBody.velocity.x = lateralVelocity.x;
vehicleBody.velocity.z = lateralVelocity.z;
Совет: моделирование сцепления с поверхностью и ограничения скорости делают управление более предсказуемым.
Для упрощения кода можно создать утилиты:
function getForwardVector(body) {
const quaternion = body.quaternion;
return new CANNON.Vec3(0, 0, 1).applyQuaternion(quaternion);
}
function applyForceInDirection(body, magnitude, directionVec) {
const force = directionVec.scale(magnitude);
body.applyForce(force, body.position);
}
Эти функции позволяют легко добавлять ускорение в любом направлении, не вычисляя вручную координаты.
Чтобы транспортное средство не переворачивалось при резких манёврах, используют:
angularDamping для ограничения вращения.body.shape.offset.y = -0.5.const speedFactor = Math.min(vehicleBody.velocity.length() / maxSpeed, 1);
steer(vehicleBody, controls.steer * (1 - speedFactor));
Так повороты становятся менее резкими на высокой скорости, что приближает поведение к реальной физике.
Эта комбинация применения сил, крутящих моментов, дампов и ограничения скорости формирует полный цикл управления объектом в Cannon.js, позволяя имитировать газ, тормоз и руль с реалистичной динамикой.