OnCollisionExit в Unity C#: конец столкновения объектов
OnCollisionExit в Unity — событие, которое вызывается, когда объект перестал касаться другого тела. Симметрично OnCollisionEnter: вход прозвучал — выход должен прозвучать. Сюда ставят «конец контакта»: убрать подсказку, выключить ток, остановить звук трения.
Условия вызова
- Как и для входа: оба объекта с коллайдерами, минимум один Rigidbody непокинематический.
- Вызывается в физическом цикле, в тот шаг FixedUpdate, на котором Unity заметила разрыв контакта.
- Принимает объект
Collisionс данными о паре.
Пример: зона трения
using UnityEngine;
public class FrictionZone : MonoBehaviour
{
private AudioSource loopSound;
private int bodiesInside = 0;
void Start()
{
loopSound = GetComponent(typeof(AudioSource)) as AudioSource;
}
void OnCollisionEnter(Collision collision)
{
bodiesInside++;
if (bodiesInside == 1)
{
loopSound.Play();
}
}
void OnCollisionExit(Collision collision)
{
// Считаем именно выходы: один вышел, второй остался
bodiesInside--;
if (bodiesInside == 0)
{
loopSound.Stop();
}
}
}
Счётчик — важный паттерн. Если в зоне одновременно несколько объектов, звук должен выключиться, только когда ушёл последний.
Важное ограничение из документации
Unity честно предупреждает: событие выхода может не прийти, если объект деактивирован или уничтожён. Чтобы отслеживать конец контакта в таких случаях, Unity пришлось бы хранить записи о всех контактирующих парах в сцене — это расходы памяти и процессора для всех проектов, включая те, которым это не нужно.
Практическое следствие: если логика критически зависит от «выхода», отслеживайте контакты сами — записывайте входящие коллайдеры и считайте их вышедшими при деактивации владельца зоны.
Пример: самостоятельный учёт контактов
using UnityEngine;
using System.Collections.Generic;
public class TrackedZone : MonoBehaviour
{
private Dictionary collidersInside = new Dictionary();
void OnCollisionEnter(Collision collision)
{
collidersInside[collision.collider] = true;
}
void OnCollisionExit(Collision collision)
{
collidersInside.Remove(collision.collider);
}
// Вызывается при выключении объекта — дописываем "выходы" вручную
void OnDisable()
{
foreach (var key in collidersInside.Keys)
{
// Обрабатываем отсутствие события выхода сами
Debug.Log("Контакт оборван: " + key.name);
}
collidersInside.Clear();
}
public bool IsEmpty()
{
return collidersInside.Count == 0;
}
}
Тот же приём документация советует и для OnTriggerExit — логика идентична, отличается только тип события.
Enter, Stay, Exit
| Событие | Когда |
|---|---|
OnCollisionEnter |
Первый кадр контакта |
OnCollisionStay |
Каждый физический шаг, пока контакт держится |
OnCollisionExit |
Кадр разрыва контакта |
Частые ошибки
1. Ожидание события при уничтожении
Destroy или SetActive(false) внутри зоны — выхода не будет. Логика, завязанная на «пустую зону», зависнет. Считайте входы и обрабатывайте прерывания.
2. Одиночный выход при нескольких телах
Выключать звук или эффект по первому же OnCollisionExit — ошибка: в зоне могли остаться другие тела. Используйте счётчик.
3. Слой и матрица физики
Если пара слоёв не проверяется физикой, выход не придёт — как и вход. Настройки проверьте в Project Settings → Physics.