Реакция на игровые события: взрывная волна, подъёмная сила

Oimo.js — это высокопроизводительная библиотека физического движка на JavaScript, ориентированная на симуляцию твёрдых тел и их взаимодействий. Она работает по принципам динамической физики, предоставляя объекты World, Body, Shape и возможности для работы с силами и коллизиями.

Создание мира и тел

Для начала работы создаётся объект мира:

const world = new OIMO.World({
    timestep: 1/60,
    iterations: 8,
    broadphase: 2, // 1: brute force, 2: sweep and prune
    gravity: [0, -9.8, 0]
});
  • timestep — шаг симуляции, влияет на точность расчётов.
  • iterations — количество итераций решателя, повышает стабильность при взаимодействии множества объектов.
  • broadphase — алгоритм предварительного поиска столкновений.
  • gravity — вектор гравитации.

Тела добавляются с помощью world.add:

const box = world.add({
    type: "box",
    size: [2, 2, 2],
    pos: [0, 5, 0],
    move: true,
    density: 1.0
});
  • type — форма объекта (box, sphere, cylinder, capsule).
  • size — размеры для каждого типа.
  • pos — начальная позиция в пространстве.
  • move — флаг, указывающий на динамическое или статическое тело.
  • density — плотность, влияет на массу.

Реализация взрывной волны

Взрывная волна создаётся путём применения силы к объектам на определённой дистанции от эпицентра. Сила направлена от точки взрыва и убывает с расстоянием.

function applyExplosion(world, epicenter, radius, power) {
    world.bodies.forEach(body => {
        if (!body.move) return; // игнорируем статические тела

        const pos = body.getPosition();
        const dir = [
            pos.x - epicenter[0],
            pos.y - epicenter[1],
            pos.z - epicenter[2]
        ];

        const dist = Math.sqrt(dir[0]**2 + dir[1]**2 + dir[2]**2);
        if (dist > radius) return;

        const forceMagnitude = power * (1 - dist / radius);
        const norm = dir.map(v => v / dist);
        const force = norm.map(v => v * forceMagnitude);

        body.applyForce(force);
    });
}
  • epicenter — точка взрыва.
  • radius — радиус действия силы.
  • power — максимальная сила у эпицентра.
  • body.applyForce(force) — метод Oimo.js для мгновенного приложения силы к телу.

Эффект взрыва можно комбинировать с визуальными эффектами и детонацией, чтобы создать реалистичную игровую механику.

Подъёмная сила и эффекты плавания

Подъёмная сила применяется к телам в жидкости или газе, моделируя эффект «подъёма» и сопротивления среды. Основной принцип — вычисление силы Архимеда и силы сопротивления.

function applyBuoyancy(body, fluidLevel, fluidDensity = 1.0, drag = 0.1) {
    const pos = body.getPosition();
    const halfHeight = body.getShape().halfHeight || 1; // пример для коробки

    if (pos.y - halfHeight < fluidLevel) {
        const submerged = Math.min(fluidLevel - (pos.y - halfHeight), 2 * halfHeight) / (2 * halfHeight);
        const buoyancyForce = fluidDensity * submerged * 9.8 * body.getMass();
        body.applyForce([0, buoyancyForce, 0]);

        const velocity = body.getLinearVelocity();
        const dragForce = velocity.map(v => -v * drag * submerged);
        body.applyForce(dragForce);
    }
}
  • fluidLevel — высота поверхности жидкости.
  • fluidDensity — плотность среды.
  • drag — коэффициент сопротивления среды.
  • submerged — доля тела, находящаяся под жидкостью.

Подъёмная сила позволяет реализовать плавание объектов, реалистичные эффекты плавучести при столкновениях и создаёт плавные динамические взаимодействия с жидкостями.

Взаимодействие с событиями

Для динамических реакций на игровые события можно объединять взрыв и подъёмную силу:

function handleEvent(world, event) {
    if (event.type === 'explosion') {
        applyExplosion(world, event.position, event.radius, event.power);
    } else if (event.type === 'flood') {
        world.bodies.forEach(body => applyBuoyancy(body, event.waterLevel, event.density, event.drag));
    }
}

Такой подход позволяет масштабировать физику на уровне мира и синхронизировать с визуальными эффектами, делая поведение объектов правдоподобным и интерактивным.

Расширенные методы управления телами

Oimo.js предоставляет методы для контроля тел:

  • body.setPosition([x, y, z]) — мгновенная установка позиции.
  • body.setLinearVelocity([vx, vy, vz]) — прямое управление скоростью.
  • body.applyImpulse([ix, iy, iz]) — кратковременное воздействие силы, имитирующее столкновение.
  • body.getRotation() и body.setRotation([x, y, z, w]) — управление ориентацией через кватернионы.

Использование этих методов позволяет создавать точные симуляции с событиями, требующими высокой точности при динамических взаимодействиях, таких как эффекты взрывов, подъёма объектов или сильного ветра.

Оптимизация производительности

Для больших сцен с множеством объектов рекомендуется:

  • Использовать broadphase: 2 для эффективного поиска столкновений.
  • Ограничивать iterations до необходимого минимума.
  • Применять силы выборочно, только к подвижным объектам.
  • Обновлять физику с фиксированным timestep для стабильности.

Эти меры обеспечивают плавное выполнение симуляции даже на сложных сценах с множеством динамических тел.