Управление: газ, тормоз, руль

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, где отрицательное значение — поворот влево, положительное — вправо.


Совмещение управления и физики

Для реалистичного поведения транспортного средства важно комбинировать линейные и угловые силы. Один из подходов — каждый кадр вычислять и применять:

  1. Ускорение или торможение вдоль локальной оси движения.
  2. Крутящий момент для поворота.
  3. Дампы для плавности движения.
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;

Совет: моделирование сцепления с поверхностью и ограничения скорости делают управление более предсказуемым.


Использование helper-функций для удобства

Для упрощения кода можно создать утилиты:

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, позволяя имитировать газ, тормоз и руль с реалистичной динамикой.