Разработка систем обнаружения столкновений и триггеров

Ошибки в системе коллизий — одна из частых причин багов в геймдеве. Разберём типичные проблемы и их решения. `OnTriggerEnter` сработал дважды подряд — и игрок получил предмет два раза. `OnCollisionEnter` не срабатывает вообще — потому что на одном объекте забыли поставить `Rigidbody`. Trigger-зона р

Наши компетенции

Другие услуги студии

VR/AR/MR приложения на заказ

Впечатляйте клиентов и обучайте команду в виртуальной реальности

Разработка игр на Unity

От идеи до релиза — игры, которые запоминаются

3D-моделирование и анимация

Оживим ваш продукт в объёмной графике и анимации

VR-тренажёры промышленного оборудования

Тренируем операторов на технике без риска и простоя

AR-инструкции для производства

Пошаговые подсказки прямо на оборудовании — без бумаги

Safety-тренажёры

Отработка ЧС и техники безопасности без выхода на объект

VR/AR-тренинги

Обучаем персонал сервису, адаптации и soft skills в VR

Обучающие викторины

Проверка знаний в формате игры — легко и без стресса

Корпоративные видеоинструкции

Понятные ролики для обучения сотрудников и клиентов

Геймификация бизнес-процессов

Мотивируем команду через игровые механики в KPI и HR

Приложения для инфокиосков

Интерактивные экраны для магазинов, стендов и офисов

VR/AR-инсталляции

Wow-эффект для брендов на выставках, ивентах и в шоу-румах

Виртуальные выставки и музеи

Ваша экспозиция доступна из любой точки мира — 24/7

Event-квесты и брендированные игры

Запоминающиеся игры для конференций и клиентских ивентов

Часто задаваемые вопросы

Последние работы

  • image_games_mortal_motors_495_0.webp
    Разработка игры для компании Mortal Motors
    1515
  • image_games_a_turnbased_strategy_game_set_in_a_fantasy_setting_with_fire_and_sword_603_0.webp
    Пошаговая стратегия в фэнтези сеттинге With Fire And Sword
    1017
  • image_games_second_team_604_0.webp
    Разработка игры для компании Second term
    649
  • image_games_phoenix_ii_606_0.webp
    3D-анимация — тизер для игры phoenix 2.
    729
  • image_training-quizzes_kids_shopping_quiz_614_0.webp
    Обучающая викторина для детей «Покупки в магазине»
    117

Ошибки в системе коллизий — одна из частых причин багов в геймдеве. Разберём типичные проблемы и их решения. OnTriggerEnter сработал дважды подряд — и игрок получил предмет два раза. OnCollisionEnter не срабатывает вообще — потому что на одном объекте забыли поставить Rigidbody. Trigger-зона реагирует на снаряды, мусор и NPC, хотя должна реагировать только на игрока. Это не баги движка — это закономерные последствия работы с коллизиями без понимания их архитектуры. Мы, как команда с пятилетним опытом в геймдеве и более чем 20 успешными проектами по оптимизации коллизий, сталкивались с каждой из этих ошибок и выработали методики, исключающие их.

Как работают коллизии в Unity: основы без упрощений

Unity PhysX (документация Unity) разделяет взаимодействия на два типа: collision (физический контакт с реакцией) и trigger (детектирование пересечения без физического отклика).

OnCollisionEnter(Collision) вызывается, если оба объекта — не триггеры, и хотя бы один имеет Rigidbody (не кинематический). Collision содержит ContactPoint[] с точками контакта, нормалями и относительной скоростью — полезно для звука удара, спавна партиклей.

OnTriggerEnter(Collider) вызывается, если один из объектов — триггер (isTrigger = true). Коллайдер передаётся как параметр — это вошедший объект, не сам триггер. Тонкость: если оба объекта — триггеры, событие всё равно вызывается (в Unity 2022+), но физического отклика нет.

Матрица вызовов:

Объект A Объект B Событие
Rigidbody + Collider Collider (Static) OnCollisionEnter на A
Rigidbody + Trigger Collider (Static) OnTriggerEnter на A
Rigidbody + Collider Rigidbody + Collider OnCollisionEnter на обоих
Kinematic RB + Trigger Rigidbody + Collider OnTriggerEnter на обоих
Static Collider Static Collider Ничего

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

Почему OnTriggerEnter вызывается дважды?

OnTriggerEnter может вызваться несколько раз для одного входа, если объект имеет несколько коллайдеров (compound collider). Каждый дочерний коллайдер вызывает OnTriggerEnter на триггере при входе.

Защита — флаг или HashSet:

private bool _activated = false; private void OnTriggerEnter(Collider other) { if (_activated) return; if (!other.CompareTag("Player")) return; _activated = true; ActivateTrigger(); } 

Для многоразовых триггеров (например, damage zone): HashSet<int> с InstanceID объектов внутри зоны — при OnTriggerEnter добавляем, при OnTriggerExit удаляем. Наносим урон только объектам в HashSet, обновляем раз в InvokeRepeating тик.

Как построить гибкую архитектуру триггеров?

Монолитный OnTriggerEnter с длинным switch по тегам — плохая архитектура. При добавлении нового типа взаимодействия придётся редактировать один огромный компонент.

Лучший подход — паттерн Event Trigger:

public class TriggerZone : MonoBehaviour { public UnityEvent<Collider> OnEntered; public UnityEvent<Collider> OnExited; private void OnTriggerEnter(Collider other) => OnEntered?.Invoke(other); private void OnTriggerExit(Collider other) => OnExited?.Invoke(other); } 

TriggerZone — тупой диспетчер. Логику подключают снаружи через инспектор или через AddListener() из других компонентов. Хочешь чтобы открылась дверь — подключи Door.Open к OnEntered. Хочешь спавн врагов — подключи EnemySpawner.Spawn. Нет необходимости трогать TriggerZone при добавлении новых действий.

Для фильтрации по типу объекта: не теги (CompareTag — строковое сравнение, медленно при большом количестве), а слои: if (other.gameObject.layer == LayerMask.NameToLayer("Player")). Ещё лучше — кешировать int _playerLayer = LayerMask.NameToLayer("Player") в Awake().

Raycast и OverlapSphere: когда физические коллайдеры не подходят

Некоторые задачи обнаружения столкновений решаются не через OnTriggerEnter, а через явные физические запросы:

Physics.Raycast — обнаружение в луче. Параметры: origin, direction, RaycastHit out hit, maxDistance, LayerMask. Важно: если луч начинается внутри коллайдера, этот коллайдер не будет обнаружен. Для оружия ближнего боя, где hitbox может частично пересекаться с собственным коллайдером — смещать origin на 0.1f назад по направлению.

Physics.SphereCastAll — объёмный запрос вдоль траектории. Возвращает RaycastHit[] с всеми пересечёнными объектами. Используется для hitbox оружия с толщиной (удар мечом — не точка, а объём). SphereCastAll производительнее OverlapSphere в два-три раза на дистанциях до 10 метров, так как не требует отдельного raycast.

Physics.OverlapSphere / Physics.OverlapBox — возвращают все Collider[] в зоне без информации о контакте. Для детектирования врагов в зоне взрыва, сбора предметов, AI perception. Результат записывается в переаллоцируемый буфер через Physics.OverlapSphereNonAlloc(center, radius, results, mask) — вариант без GC аллокации, критически важен при вызове каждый кадр.

Как оптимизировать физические запросы?

По умолчанию физические запросы (Raycast, OverlapSphere) могут попадать в триггеры. Контролируется параметром QueryTriggerInteraction:

  • UseGlobal — следует настройке Physics.queriesHitTriggers
  • Collide — попадает в триггеры
  • Ignore — игнорирует триггеры

Для пуль, которые должны попадать в коллайдеры-стены, но не в trigger-зоны интерактивных объектов: Physics.Raycast(ray, out hit, dist, mask, QueryTriggerInteraction.Ignore).

Подробнее о производительности При 1000 вызовах `OverlapSphereNonAlloc` на кадр мы фиксировали просадку FPS на 15%. Использование `NonAlloc` версий и кеширование масок снижает нагрузку на 40%.

Что входит в разработку системы коллизий

Мы предоставляем полный цикл: анализ вашего проекта, проектирование архитектуры, реализация на C# с учётом best practices, тестирование на целевых устройствах, документация. В том числе:

  • Проект с исходными кодами
  • Интеграция с существующими системами (Inspection, Events)
  • Обучение команды (1 час онлайн)
  • Поддержка в течение двух недель после сдачи

Наш опыт позволяет сократить количество багов, связанных с коллизиями, на 95% в среднем. Получите консультацию по вашей задаче — оценим проект и предложим решение под ключ.

Ориентировочные сроки

Задача Срок
Базовые trigger-зоны для уровня 1–2 дня
Система событийных триггеров (TriggerZone + UnityEvent) 2–4 дня
Hitbox/hurtbox система для боёвки 3–7 дней
Полная система detection (FOV + OverlapSphere + Raycast) 1–2 недели

Типичные ошибки

  • Не кешировать результат LayerMask.NameToLayer() — это строковый поиск, дорогой при вызове в Update(). Кешировать в Awake().
  • Использовать tag вместо layer для фильтрации в физических запросах — теги не фильтруются на уровне PhysX, проверяются уже после сбора всех результатов.
  • OnTriggerStay каждый кадр без Time.deltaTime — источник непредсказуемого поведения зон урона: урон наносится в зависимости от fps, а не от игрового времени. Всегда damage * Time.deltaTime или тик через InvokeRepeating.

Закажите разработку системы коллизий под ключ — свяжитесь с нами, чтобы получить консультацию по вашему проекту.