Зоны-триггеры: Area2D

Area2D — это зона, которая не толкает объекты, а только замечает, кто в неё вошёл и вышел.

Суть: тело (CharacterBody2D) физически отталкивается, а область (Area2D) просто срабатывает как датчик, когда что-то её пересекает.

Не всякое столкновение должно толкать. Когда персонаж подбирает монетку, монетка не должна отбрасывать его — она должна исчезнуть и добавить очко. Когда герой входит в зону шипов, он не врезается в стену — он получает урон. Для таких «датчиков» в Godot есть узел Area2D. Это область с формой столкновения, но без физического отталкивания: она просто замечает, что в неё что-то вошло, и сообщает об этом сигналом.

Главные сигналы Area2D — body_entered (в зону вошло тело, например персонаж) и body_exited (вышло). Есть и area_entered — когда в зону вошла другая область. Эти сигналы дают тебе момент, когда нужно среагировать: собрать монету, нанести урон, открыть дверь.

extends Area2D  # это монетка

signal collected

func _ready() -> void:
    body_entered.connect(_on_body_entered)

func _on_body_entered(body: Node2D) -> void:
    if body.name == "Player":
        collected.emit()
        queue_free()  # убрать монетку из игры

Здесь монетка-Area2D подписывается на собственный сигнал body_entered. Когда в неё входит игрок, она шлёт свой сигнал collected (на него отреагирует счётчик очков) и удаляет себя через queue_free(). Никакого отталкивания — чистый датчик.

Стоит уловить общий принцип: Area2D отделяет «что-то произошло» от «что с этим делать». Сама зона лишь честно сообщает о входе и выходе, а реакция — собрать монету, нанести урон, открыть дверь — живёт в обработчике, который ты подключаешь. Благодаря этому одну и ту же область легко переиспользовать: сегодня она монета, завтра — зона лечения, послезавтра — триггер катсцены, и меняется лишь обработчик, а не сам механизм обнаружения. Такое разделение «датчик отдельно, реакция отдельно» делает игру гибкой и понятной.

Как работает под капотом

Каждый кадр движок проверяет, какие тела и области пересекаются с Area2D. Он сравнивает текущий список «кто внутри» с прошлым. Появился новый — летит сигнал body_entered. Кто-то пропал — body_exited. То есть область хранит множество объектов внутри себя и реагирует на изменения этого множества.

class Area:
    def __init__(self):
        self.inside = set()

    def update(self, overlapping):
        overlapping = set(overlapping)
        for body in overlapping - self.inside:
            print(f"body_entered: {body}")
        for body in self.inside - overlapping:
            print(f"body_exited: {body}")
        self.inside = overlapping

coin = Area()
coin.update(["Player"])          # игрок вошёл
coin.update(["Player"])          # всё ещё внутри — тихо
coin.update([])                   # игрок вышел

Та же логика на Python ▶. Сигналы entered/exited — это разница множеств «кто внутри сейчас» и «кто был раньше». Запусти и увидишь: повторное присутствие сигнал не шлёт, только вход и выход.

Стоит запомнить про порядок жизни подобранного объекта. Когда монета вызывает queue_free(), она не исчезает мгновенно — движок помечает её на удаление и убирает в конце кадра, аккуратно отвязав от дерева и физики. Это сделано специально, чтобы не сломать обход, который как раз идёт. Тебе достаточно правила: вызвал queue_free() — считай, что узла больше нет, и не трогай его дальше в этом же обработчике. Если нужно что-то сделать «вместо» монеты (звук, эффект), сделай это до queue_free или поручи другому узлу.

Частые ошибки

Частая ошибка — ждать от Area2D отталкивания: область не толкает, она только сообщает. Если нужна стена — это StaticBody2D, а не Area2D. Вторая — забыть подключить сигнал (connect) или галочку в редакторе: тогда вход в зону есть, а реакции нет. Третья — звать queue_free() и тут же обращаться к узлу: после queue_free узел помечен на удаление, не трогай его дальше. Четвёртая — проверять body по имени строкой "Player" хрупко; надёжнее проверять группу или тип, но для старта имя сойдёт.

Best practices

Используй Area2D для всего, что должно срабатывать, но не толкать: монеты, чекпоинты, зоны урона, триггеры катсцен. Подключай сигналы и реагируй в обработчиках, а не опрашивай область каждый кадр вручную. Для удаления подобранного объекта зови queue_free() и больше к нему не обращайся. Проверяй, кто вошёл (через группы), чтобы зона реагировала только на нужные объекты.

Итоги: Area2D — датчик-зона: замечает вход и выход, но не толкает. Сигналы body_entered/body_exited дают момент реакции — собрать монету, нанести урон. Под капотом это разница множеств «кто внутри». Подключай сигналы и удаляй подобранное через queue_free.

Проверьте себя
1. Чем Area2D отличается от физического тела вроде StaticBody2D?
AArea2D невидима, тело видимо
BArea2D только замечает вход/выход и не толкает, а тело физически останавливает
CArea2D быстрее
DМежду ними нет разницы
2. Какой сигнал Area2D сработает, когда в зону монетки войдёт персонаж?
Abody_exited
Bbody_entered
Ctree_exited
Dready