Фильтрация столкновений через collision groups

Фильтрация столкновений является одной из ключевых возможностей физических движков, позволяющей контролировать, какие объекты могут взаимодействовать друг с другом. В библиотеке Oimo.js используется система collision groups, которая обеспечивает гибкое управление столкновениями между телами.

Принцип работы collision groups

Каждое тело в Oimo.js может быть отнесено к одной или нескольким группам столкновений, представленных в виде битовых масок. Это позволяет задавать правила, по которым тело будет реагировать на другие объекты.

Основные элементы фильтрации:

  1. group — собственная группа тела. Каждое тело принадлежит одной группе, которая задается числом (битовой маской).
  2. mask — определяет, с какими группами тело может сталкиваться. Тело сталкивается только с теми объектами, у которых группа совпадает с маской.

Физический движок проверяет столкновения по следующему правилу:

(bodyA.group & bodyB.mask) !== 0 && (bodyB.group & bodyA.mask) !== 0

Если условие истинно, столкновение учитывается в симуляции; если ложно — объекты проходят сквозь друг друга без реакции.

Создание тел с фильтрацией

Для задания collision group при создании тела используется свойство group объекта конфигурации, а для mask — свойство mask.

Пример создания двух тел с фильтрацией:

import * as OIMO from 'oimo';

const world = new OIMO.World();

// Тело принадлежит группе 1, сталкивается только с группой 2
const boxA = world.add({
    type: 'box',
    size: [1, 1, 1],
    pos: [0, 5, 0],
    move: true,
    group: 1,
    mask: 2
});

// Тело принадлежит группе 2, сталкивается с группой 1
const boxB = world.add({
    type: 'box',
    size: [1, 1, 1],
    pos: [0, 0, 0],
    move: false,
    group: 2,
    mask: 1
});

В данном примере boxA будет реагировать только на boxB, и наоборот. Любые другие тела, которые не входят в соответствующую группу, будут игнорироваться.

Работа с несколькими группами

Одно тело может принадлежать сразу нескольким группам. Для этого используется побитовое ИЛИ (|) при указании числа группы и маски:

const boxC = world.add({
    type: 'sphere',
    size: [0.5],
    pos: [2, 5, 0],
    move: true,
    group: 1 | 4,   // тело принадлежит группе 1 и 4
    mask: 2 | 8     // сталкивается с группами 2 и 8
});

Таким образом, boxC будет сталкиваться с объектами из групп 2 и 8, но не с объектами, которые принадлежат только к 1 или 4, если они не входят в маску.

Изменение групп и масок на лету

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

// Добавление тела в новую группу
boxA.group |= 4; // теперь тело принадлежит группам 1 и 4

// Изменение маски столкновений
boxA.mask = 2 | 8; // теперь тело сталкивается с группами 2 и 8

При изменении масок столкновений Oimo.js учитывает новые правила сразу, без необходимости пересоздавать тело.

Практические сценарии использования

  • Разделение слоев взаимодействия: объекты окружения могут находиться в одной группе, а игрок и его снаряды — в другой, чтобы исключить нежелательные столкновения.
  • Фильтрация между типами объектов: группы позволяют создавать правила, по которым разные виды объектов реагируют друг на друга. Например, враги могут сталкиваться с игроком, но игнорировать других врагов.
  • Оптимизация производительности: уменьшение количества проверок столкновений снижает нагрузку на физический движок.

Рекомендации по проектированию

  • Использовать битовые значения степени двойки (1, 2, 4, 8 и т.д.) для групп, чтобы легко комбинировать их через побитовое ИЛИ.
  • Разрабатывать маски с учётом всех потенциальных взаимодействий. При сложных сценах полезно вести таблицу групп и масок для наглядности.
  • Проверять фильтрацию в отладочном режиме, чтобы убедиться, что объекты взаимодействуют только там, где нужно.

Фильтрация через collision groups предоставляет мощный инструмент управления физическим взаимодействием объектов, позволяя создавать сложные и оптимизированные симуляции с минимальными избыточными проверками столкновений.