Коротко. Коллайдер задаёт форму объекта для физики, а Rigidbody2D заставляет объект двигаться по её законам. Обычные коллайдеры сталкиваются и вызывают OnCollisionEnter2D. Коллайдер с галочкой Is Trigger пропускает объекты сквозь себя и вызывает OnTriggerEnter2D. Чтобы событие сработало, хотя бы у одного из двух объектов должен быть Rigidbody2D, а проверить что-то на расстоянии поможет Physics2D.Raycast(origin, direction, distance, layers).
Ниже: готовый код под Unity 6.6, таблица всех сочетаний коллайдеров, измеренная в редакторе, и чеклист на случай, когда событие молчит или объект проваливается сквозь пол.
Почти все вопросы новичков про физику сводятся к трём: почему объекты не сталкиваются, почему триггер молчит и почему персонаж упал сквозь пол. На форумах на них отвечают обрывками, и половина ответов написана для старых версий движка. Поэтому мы не стали пересказывать документацию, а собрали демо-сцену в Unity 6.6 (6000.6) и прогнали в Play Mode все сочетания типов коллайдеров. Цифры ниже взяты из этого теста, весь код из статьи компилируется в этой версии без предупреждений.
Тест пригодился сразу. Пока мы собирали сцену, герой провалился сквозь пол, хотя компонент Box Collider 2D на полу был. Оказалось, что коллайдер добавили до назначения спрайта, и он получил нулевой размер. Такие ошибки не видны в консоли, поэтому в конце статьи есть отдельный чеклист.
Что такое коллайдер, триггер и Rigidbody
Коллайдер — это невидимая форма объекта, по которой физика определяет касания: Box Collider 2D, Circle Collider 2D, Capsule Collider 2D. Триггер — тот же коллайдер с включённой галочкой Is Trigger: он не мешает движению, а только сообщает, что в него кто-то вошёл. Rigidbody2D — компонент, который подключает объект к физическому движку.
Поведение объекта задаёт поле Body Type в Rigidbody2D:
- Dynamic — обычный физический объект: падает, толкается, сталкивается. Так настраивают героя, врагов и ящики.
- Kinematic — двигается только из кода, силы на него не действуют. Подходит для движущихся платформ.
- Static — не двигается. Полу и стенам
Rigidbody2Dвообще не нужен: объект с одним коллайдером и так считается статичным.
Шаг 1. Столкновения: OnCollisionEnter2D
Событие OnCollisionEnter2D вызывается в момент удара двух обычных коллайдеров, если хотя бы один из них принадлежит объекту с Rigidbody2D в режиме Dynamic. Настройте сцену так: герою добавьте Rigidbody2D и Capsule Collider 2D, полу и стене только Box Collider 2D. Подробно про настройку персонажа мы писали в статье про движение и прыжок в Unity 2D.
Создайте скрипт HardLanding и добавьте его герою. Он узнаёт силу удара и отличает пол от стены: relativeVelocity хранит скорость столкновения, а нормаль показывает, с какой стороны пришёлся удар.
using UnityEngine;
public class HardLanding : MonoBehaviour
{
[SerializeField] private float dangerSpeed = 8f;
// Вызывается в момент удара двух обычных (не триггерных) коллайдеров
private void OnCollisionEnter2D(Collision2D collision)
{
float hitSpeed = collision.relativeVelocity.magnitude;
Vector2 normal = collision.GetContact(0).normal;
Debug.Log($"Удар о {collision.gameObject.name}: скорость {hitSpeed:F1}, нормаль {normal}");
// normal.y > 0.5 — удар пришёлся снизу, то есть это пол, а не стена
if (hitSpeed >= dangerSpeed && normal.y > 0.5f)
Debug.Log("Жёсткое приземление!");
}
}
В нашей сцене герой упал с высоты 5 метров, и консоль показала Удар о Floor: скорость 17,1, нормаль (0.00, 1.00). Пара к этому методу: OnCollisionStay2D работает, пока объекты соприкасаются, а OnCollisionExit2D вызывается, когда они разошлись.
Шаг 2. Триггер: OnTriggerEnter2D
Триггер нужен там, где важен сам факт входа в зону, а препятствие не нужно: монеты, урон от шипов, чекпоинты, финиш уровня. Добавьте монете Circle Collider 2D, включите Is Trigger и повесьте на неё скрипт:
using UnityEngine;
public class CoinPickup : MonoBehaviour
{
[SerializeField] private int score = 1;
// Вызывается, когда что-то вошло в зону с галочкой Is Trigger
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
Debug.Log($"Монета подобрана: +{score}");
Destroy(gameObject);
}
}
Не забудьте выбрать герою тег Player в верхней части инспектора. Сравнивать тег лучше через CompareTag, а не через other.tag == "Player": так нет лишних выделений памяти, а ошибка в имени тега сразу видна в консоли.
Какие сочетания коллайдеров срабатывают
Событие сработает не при любом сочетании объектов. В тесте мы столкнули все 21 пару типов и посчитали вызовы. «Static» здесь значит объект с одним коллайдером, без Rigidbody2D.
| Static | Dynamic | Kinematic | Static триггер | Dynamic триггер | Kinematic триггер | |
|---|---|---|---|---|---|---|
| Static | нет | Collision | нет | нет | Trigger | Trigger |
| Dynamic | Collision | Collision | Collision | Trigger | Trigger | Trigger |
| Kinematic | нет | Collision | нет | Trigger | Trigger | Trigger |
| Static триггер | нет | Trigger | Trigger | нет | Trigger | Trigger |
| Dynamic триггер | Trigger | Trigger | Trigger | Trigger | Trigger | Trigger |
| Kinematic триггер | Trigger | Trigger | Trigger | Trigger | Trigger | Trigger |
Из таблицы следуют три правила, которые стоит запомнить:
- Столкновение требует Dynamic. Две Kinematic-платформы пройдут друг сквозь друга без единого события.
- Триггеру хватает любого Rigidbody2D у одного из двух объектов. Два объекта с одними коллайдерами молчат всегда.
- Событие получают оба объекта, поэтому скрипт можно вешать на любой из них. Если коллайдер висит на дочернем объекте, а
Rigidbody2Dна родителе, событие придёт и туда, и туда: мы проверили.
Шаг 3. Raycast: проверка лучом
Physics2D.Raycast запускает невидимый луч и сообщает, во что он попал. Луч нужен, когда касания ещё нет: враг видит игрока, выстрел без пули, проверка пропасти впереди. Метод возвращает RaycastHit2D: при попадании в нём есть collider, point и distance, при промахе collider равен null.
using UnityEngine;
public class RaySensor : MonoBehaviour
{
[SerializeField] private float distance = 6f;
[SerializeField] private LayerMask hitLayers;
private void Update()
{
Vector2 origin = transform.position;
Vector2 direction = transform.right;
RaycastHit2D hit = Physics2D.Raycast(origin, direction, distance, hitLayers);
if (hit.collider != null)
{
Debug.DrawLine(origin, hit.point, Color.red);
Debug.Log($"Луч попал в {hit.collider.name} на расстоянии {hit.distance:F2}");
}
else
{
Debug.DrawRay(origin, direction * distance, Color.green);
}
}
}
В инспекторе в поле Hit Layers отметьте слой, в который должен попадать луч, например Ground. Debug.DrawLine рисует линию только в редакторе, в окне Scene, поэтому в игре её не будет. Debug.Log здесь для наглядности: в настоящей игре вызов каждый кадр лучше убрать.
Две ловушки Raycast. Настройки по умолчанию проверены в тесте. Queries Start In Colliders включён: луч из центра объекта без LayerMask попадает в собственный коллайдер на расстоянии 0. Queries Hit Triggers включён: луч остановится на триггере перед стеной. Лечится LayerMask без своего слоя и без слоя триггеров, либо галочками в Project Settings → Physics 2D.
Почему OnTriggerEnter2D или OnCollisionEnter2D не срабатывает
Чаще всего событие молчит из-за одной из семи причин. Проверяйте их по порядку и поставьте первой строкой метода Debug.Log, чтобы понять, вызывается ли он вообще.
- Нет Rigidbody2D. Нужен хотя бы у одного объекта, смотрите таблицу выше.
- Не тот Is Trigger. Если галочка стоит хотя бы у одного объекта, сработает
OnTriggerEnter2D, аOnCollisionEnter2Dнет. - Метод из 3D.
OnTriggerEnterбез «2D» на 2D-коллайдерах не вызывается: в тесте 0 вызовов и никакой ошибки в консоли. - Опечатка в имени.
onTriggerEnter2Dс маленькой буквы тоже даёт 0 вызовов и молчание компилятора. - Неверный тип параметра.
OnTriggerEnter2D(Collision2D c)не вызовется, зато Unity напишет в консоль:Script error: OnTriggerEnter2D. This message parameter has to be of type: Collider2D. - Слои не взаимодействуют. Откройте Edit → Project Settings → Physics 2D → Layer Collision Matrix. Если галочка на пересечении двух слоёв снята, не будет ни столкновения, ни триггера.
- Не совпал тег. Метод сработал, но
CompareTagвернулfalse, потому что герою не назначен тегPlayer.
Почему объект проваливается сквозь пол
Объект проваливается, когда физика не видит контакта. Проверьте по порядку: есть ли у пола Collider2D, не включён ли Is Trigger у пола или героя и не равен ли нулю размер коллайдера. Размер смотрите в поле Size: если Box Collider 2D добавлен до назначения спрайта, там будет ноль, и контактов не будет.
Если объект пролетает препятствие только на большой скорости, это туннелирование. Физика считается шагами по 0,02 секунды, и быстрый объект просто перепрыгивает тонкую стену между шагами. Мы запустили по 20 «пуль» размером 0,2 в стену толщиной 0,2:
| Скорость | Discrete (по умолчанию) | Continuous |
|---|---|---|
| 20 | пролетели 8 из 20 | 0 из 20 |
| 100 | пролетели 15 из 20 | 0 из 20 |
| 300 | пролетели 20 из 20 | 0 из 20 |
Вывод простой: быстрым объектам ставьте Collision Detection: Continuous в Rigidbody2D. Стоит чуть дороже по производительности, поэтому включайте его только там, где скорость реально большая: герою, пулям, снарядам.
Чем физика в 3D отличается от 2D
Логика в 3D та же, но это отдельный движок с другими классами. Смешивать их нельзя: 2D-коллайдер не столкнётся с 3D-коллайдером.
| Что | 2D | 3D |
|---|---|---|
| Тело | Rigidbody2D | Rigidbody |
| Столкновение | OnCollisionEnter2D(Collision2D) | OnCollisionEnter(Collision) |
| Триггер | OnTriggerEnter2D(Collider2D) | OnTriggerEnter(Collider) |
| Луч | Physics2D.Raycast вернёт RaycastHit2D | Physics.Raycast вернёт bool, попадание в out RaycastHit |
Вывод
Обычный коллайдер останавливает, триггер сообщает, луч проверяет на расстоянии, а Rigidbody2D у одного из объектов запускает всю эту механику. Если событие молчит, идите по чеклисту, а быстрым объектам сразу ставьте Continuous.
Если движок ещё не установлен, начните с установки Unity и первого проекта, а если пока непонятно, что такое GetComponent и SerializeField, загляните в основы C# для Unity. Собрать из этих механик целую игру с проверкой заданий можно на бесплатном курсе Unity Старт и дальше по полной программе.
Частые вопросы
Чем коллайдер отличается от триггера в Unity?
Обычный коллайдер физически останавливает другие объекты и вызывает OnCollisionEnter2D. Коллайдер с галочкой Is Trigger пропускает объекты сквозь себя и вызывает OnTriggerEnter2D. Триггеры используют для монет, зон урона, финиша и других областей.
Почему не срабатывает OnTriggerEnter2D?
Чаще всего ни у одного из двух объектов нет Rigidbody2D, не стоит галочка Is Trigger, слои отключены в Layer Collision Matrix или метод назван неверно. В 2D нужен именно OnTriggerEnter2D(Collider2D other): версия без 2D и написание с маленькой буквы не вызываются.
Почему объект проваливается сквозь пол в Unity?
Проверьте, что у пола есть Collider2D с ненулевым размером и что у объекта не включён Is Trigger. Если объект пролетает пол только на большой скорости, поставьте в Rigidbody2D режим Collision Detection: Continuous.
Что такое Raycast в Unity?
Raycast — это невидимый луч, который проверяет, во что он попал на заданном расстоянии. В 2D его запускают через Physics2D.Raycast(origin, direction, distance, layerMask): метод возвращает RaycastHit2D, а при промахе его collider равен null.
Нужен ли Rigidbody на обоих объектах?
Нет. Для столкновения нужен хотя бы один объект с Rigidbody2D в режиме Dynamic. Для триггера достаточно, чтобы Rigidbody2D в режиме Dynamic или Kinematic был хотя бы у одного из двух объектов.


