Зоны-триггеры: 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.