Розробка систем виявлення зіткнень та тригерів

Помилки в системі колізій — одна з частих причин багів у геймдеві. Розберемо типові проблеми та їх рішення. `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, хоча повинна реагувати тільки на гравця. Це не баги рушія — це закономірні наслідки роботи з колізіями без розуміння їх архітектури. Ми, як команда з 5+ роками досвіду в геймдеві та понад 20 успішними проєктами з оптимізації колізій, стикалися з кожною з цих помилок і виробили методики, що виключають їх. Ми на ринку з 2019 року, гарантуємо якість і маємо сертифікованих розробників Unity.

Як працюють колізії в 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 в 2-3 рази при радіусі до 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` версій знижує навантаження на 30–40%. Кешування масок додатково економить 10% CPU.

Що входить у розробку системи колізій

Ми надаємо повний цикл: аналіз вашого проєкту, проектування архітектури, реалізація на C# з урахуванням best practices, тестування на цільових пристроях, документація. Вартість базової системи від $500, повної — від $2000. У тому числі:

  • Проєкт з вихідними кодами
  • Інтеграція з існуючими системами (Inspection, Events)
  • Навчання команди (1 година онлайн)
  • Підтримка протягом двох тижнів після здачі

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

Орієнтовні терміни

Завдання Термін Вартість
Базові trigger-зони для рівня 1–2 дні від $500
Система подійних тригерів (TriggerZone + UnityEvent) 2–4 дні від $1000
Hitbox/hurtbox система для бою 3–7 днів від $1500
Повна система detection (FOV + OverlapSphere + Raycast) 1–2 тижні від $2000

Типові помилки

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

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