Collision groups и collision masks: фильтрация столкновений

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

В Cannon.js каждый Body может быть назначен в одну или несколько групп и иметь маску столкновений. Эти параметры определяют поведение тела при проверке столкновений с другими объектами.


Collision Groups

Collision group — это числовой битовый флаг, который определяет принадлежность тела к определенной группе столкновений.

const body = new CANNON.Body({
    mass: 1,
    shape: new CANNON.Sphere(1)
});
body.collisionFilterGroup = 1; // Присваиваем тело к группе 1
  • Тип значения: число (целое), обычно степень двойки (1, 2, 4, 8…), чтобы можно было использовать побитовые операции.
  • Назначение: разделить объекты по логическим группам (например, “игроки”, “стены”, “пули”).
  • Особенности: объект может принадлежать к одной группе, или можно объединять группы через побитовое ИЛИ (|).

Пример с объединением групп:

body.collisionFilterGroup = 1 | 2; // Тело принадлежит одновременно к группам 1 и 2

Collision Masks

Collision mask определяет, с какими группами объектов тело может сталкиваться.

body.collisionFilterMask = 1; // Тело будет сталкиваться только с объектами из группы 1
  • Тип значения: число (целое), также как битовый флаг.
  • Логика работы: при проверке столкновения Cannon.js выполняет побитовое И collisionFilterGroup одного тела с collisionFilterMask другого и наоборот. Если результат не равен нулю, столкновение происходит.

Пример проверки:

bodyA.collisionFilterGroup & bodyB.collisionFilterMask !== 0 &&
bodyB.collisionFilterGroup & bodyA.collisionFilterMask !== 0

Если выражение истинно, объекты могут взаимодействовать.


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

  1. Изоляция определенных объектов Игровые объекты, которые не должны сталкиваться между собой (например, пули одного игрока), можно поместить в отдельную группу и настроить маску так, чтобы они взаимодействовали только с окружением.

    const playerBullets = new CANNON.Body({ mass: 1, shape: new CANNON.Sphere(0.1) });
    playerBullets.collisionFilterGroup = 2;
    playerBullets.collisionFilterMask = 1; // Только с окружением
  2. Создание сложной сцены с множеством групп В симуляции с NPC, игроком, стенами и динамическими объектами можно распределить группы:

    • 1 — статические объекты (стены, пол)
    • 2 — игрок
    • 4 — NPC
    • 8 — пули

    Тогда маски можно задать так, чтобы пули сталкивались только со стенами и NPC, игрок мог столкнуться с NPC и стенами, а NPC — только с игроком и стенами.

    player.collisionFilterGroup = 2;
    player.collisionFilterMask = 1 | 4; // Столкновение со стенами и NPC
    
    npc.collisionFilterGroup = 4;
    npc.collisionFilterMask = 1 | 2; // Столкновение со стенами и игроком
    
    bullet.collisionFilterGroup = 8;
    bullet.collisionFilterMask = 1 | 4; // Столкновение со стенами и NPC
  3. Оптимизация производительности Ограничение лишних проверок столкновений снижает нагрузку на физический движок. В больших сценах использование масок особенно эффективно, когда сотни объектов перемещаются одновременно.


Побитовая логика фильтрации

  • Группы: каждая степень двойки представляет отдельную группу.
  • Маска: побитовое И с группой определяет допустимые столкновения.

Пример:

const WALL = 1;   // 0001
const PLAYER = 2; // 0010
const ENEMY = 4;  // 0100
  • Тело с collisionFilterGroup = PLAYER и collisionFilterMask = WALL | ENEMY (0010 & 0001, 0010 & 0100) столкнется с объектами WALL и ENEMY.
  • Тело с collisionFilterGroup = ENEMY и collisionFilterMask = WALL столкнется только со стенами.

Советы по организации

  • Использовать степени двойки для всех групп.
  • Маски могут включать несколько групп через побитовое ИЛИ.
  • Для больших сцен рекомендуется документировать все группы, чтобы избежать путаницы.
  • Проверять правильность масок при динамическом создании объектов, чтобы не появлялись неожиданные столкновения.

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