Unity C#

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.

Связанные статьи