Обнаружение столкновений в Godot 4

Введение
Обнаружение столкновений (collision detection) — это процесс определения пересечения физических примитивов в игровом мире. Оно отвечает за то, когда персонаж наступает на платформу, попадает на снаряд или отталкивается от стены. Правильно настроенное обнаружение делает механику игры предсказуемой и приятной для игрока.
В Godot 4 есть готовые ноды и API для физики, которые позволяют сочетать простые и эффективные формулы с гибкими настройками слоёв и масок столкновений. Этот материал подходит для 2D-платформера, но многие принципы применимы в 3D.
Что нужно подготовить
- Godot 4 (рекомендуется последняя стабильная ветка).
- Новая сцена с узлом CharacterBody2D в качестве корня.
- Sprite2D (или AnimatedSprite2D) для визуала игрока.
- StaticBody2D для платформ и препятствий.
Код из статьи свободен под MIT (указано в исходном материале).
Быстрый пример движения игрока
Ниже — упрощённый пример обработки ввода и движения с использованием move_and_collide. Этот пример демонстрационный; для платформера добавьте гравитацию и прыжок.
extends CharacterBody2D
var speed := 300
func _physics_process(delta: float) -> void:
var input_dir := Vector2.ZERO
if Input.is_action_pressed("ui_left"):
input_dir.x -= 1
if Input.is_action_pressed("ui_right"):
input_dir.x += 1
if Input.is_action_pressed("ui_up"):
input_dir.y -= 1
if Input.is_action_pressed("ui_down"):
input_dir.y += 1
velocity = input_dir.normalized() * speed
var collision = move_and_collide(velocity * delta)
if collision:
print("collided with: ", collision.get_collider())Важно: move_and_collide возвращает объект столкновения при пересечении; можно читать нормали, позицию касания и ссылку на коллайдер.
Типы форм столкновений и когда их использовать
Godot предоставляет несколько базовых форм в 2D. Правильный выбор влияет на производительность и поведение столкновений.
Круг (CircleShape2D)
- Лучшее применение: круглые персонажи, шарики, объекты, где важна радиальная симметрия.
- Плюсы: дешёвая проверка, плавные отскоки без углов.
- Минусы: плохо подходит для коробочных форм.
Пример создания в коде:
var collision_shape := CollisionShape2D.new()
var circle_shape := CircleShape2D.new()
circle_shape.radius = 32
collision_shape.shape = circle_shape
add_child(collision_shape)Прямоугольник (RectangleShape2D)
- Применение: платформеры, враги с прямоугольным хитбоксом, объекты уровня.
- Плюсы: простая геометрия, хорошо моделирует боковые столкновения и земля.
- Минусы: углы могут застревать в узких проходах.
var collision_shape := CollisionShape2D.new()
var rect_shape := RectangleShape2D.new()
rect_shape.extents = Vector2(32, 64)
collision_shape.shape = rect_shape
add_child(collision_shape)Выпуклый многоугольник (ConvexPolygonShape2D)
- Применение: сложные стабильно выпуклые формы для точного соответствия силуэту.
- Плюсы: лучшее соответствие внешнему контуру, стабильная физика.
- Минусы: дороже в расчётах, нельзя задавать вогнутые контуры.
var collision_shape := CollisionShape2D.new()
var polygon_shape := ConvexPolygonShape2D.new()
polygon_shape.set_points([Vector2(-32, -64), Vector2(32, -64), Vector2(0, 64)])
collision_shape.shape = polygon_shape
add_child(collision_shape)Совет: комбинируйте несколько простых форм вместо одной сложной — это часто проще для поддержки и быстрее по производительности.
Обнаружение столкновений в процессе физики
Выше мы пример показал move_and_collide. Ещё один распространённый способ — move_and_slide (или аналогичная логика у CharacterBody2D) для характерного поведения персонажа при скольжении по поверхностям.
Пример с обработкой столкновения:
func _physics_process(delta: float) -> void:
# ... ввод и вычисление velocity
var collision = move_and_collide(velocity * delta)
if collision:
var other = collision.get_collider()
if other:
print("Столкновение с:", other.name)
# можно читать collision.get_position(), get_normal() и другие поляПолезно использовать методы столкновения для получения нормали поверхности и корректного отражения или отскока.
Сигналы столкновений и группы
Сигналы позволяют реагировать на контактные события, не проверяя всё вручную.
body_entered и body_exited
Эти сигналы отправляют узел, когда другой PhysicsBody2D входит или выходит из зоны столкновения (например, Area2D или CollisionObject2D). Это удобно для триггеров, коллекционных предметов и зон событий.
Пример реакции на коллекционный предмет:
func _ready() -> void:
connect("body_entered", Callable(self, "_on_body_entered"))
func _on_body_entered(body: Node) -> void:
if body.is_in_group("collectible"):
play_collectible_sound()
body.queue_free()Заметьте: используйте группы для логического разделения типов объектов (collectible, enemy, platform).
Слои и маски столкновений
Слои и маски дают битовый контроль над тем, что с чем взаимодействует. Это критично для производительности и предсказуемого поведения.
Пример сценария:
- Игрок и враги должны сталкиваться с платформами.
- Враги не должны сталкиваться друг с другом.
- Пули должны взаимодействовать только с врагами, но не с платформами.
Реализация (псевдокод в GDScript):
# В скрипте врага
func _ready() -> void:
# отключить маску столкновения с другими врагами (слой 2)
set_collision_mask_value(2, false)
# включить столкновения с платформами (слой 3)
set_collision_mask_value(3, true)
# В скрипте пули
func _ready() -> void:
set_collision_mask_value(2, true) # пуля должна бить врагов
set_collision_mask_value(3, false) # пуля не должна бить платформыХорошая практика: документируйте назначение слоёв в проекте (например, 1 — игрок, 2 — враги, 3 — платформа, 4 — пули).
Практические рекомендации и шаблоны
Используйте простые формы
По возможности используйте круги и прямоугольники. Они быстрее и предсказуемее в поведении.
Гибридный хитбокс
Комбинируйте несколько CollisionShape2D для игрока: один для земли, другой для боков и верхней части. Это даёт точный контроль столкновений для разных ситуаций (столкновение с платформой vs зацеп за угол).
Bounding boxes перед точной проверкой
Сначала проверяйте простую AABB-бокс проверку (get_global_transform().xform_rect() или area overlap), затем выполняйте точную физическую проверку. Это уменьшает число дорогих вычислений.
Частые оптимизации
- Сократите количество активных физических тел.
- Переводите неактивные объекты в статические или выключайте коллайдеры.
- Используйте слои, чтобы исключить лишние пересечения.
Отладка и проверка коллизий
- Включите «Visible Collision Shapes» в отладчике Godot — вы увидите все формы коллайдеров.
- Печайте сведения о столкновении: нормали, позиции, имя коллайдера.
- Тестируйте граничные случаи: очень высокие скорости (трассировка сквозь объекты), узкие проходы, последовательные столкновения.
Методика внедрения (мини-SOP)
- Создайте базовую сцену с CharacterBody2D и StaticBody2D платформ.
- Назначьте простые CollisionShape2D (прямоугольник/круг).
- Определите схемy слоёв и масок и задокументируйте их.
- Добавьте сигналы для предметов и зон.
- Протестируйте базовые столкновения в режиме отладки.
- Оптимизируйте формы и выключайте ненужные физические тела.
План тестирования и критерии приёмки
Критерии приёмки:
- Игрок не проходит сквозь платформы при нормальных скоростях.
- Коллекционные предметы удаляются и дают эффект при касании.
- Пули попадают в врагов и не взаимодействуют с платформами.
- Враги не сталкиваются друг с другом, если это запланировано.
Тесты принятия:
- unit-тесты сценариев столкновений (при наличии тестовой инфраструктуры).
- ручное тестирование в редакторе с включёнными видимыми коллайдерами.
- стресс-тест: сотни объектов с выключенными физическими расчётами для неактивных.
Отказоустойчивость: когда подход может не сработать
- Высокоскоростные объекты могут «пролетать» сквозь мелкие коллайдеры — для них используйте трассировку (raycast) или увеличивайте шаг проверки.
- Сложные вогнутые формы: ConvexPolygon не подходит для вогнутых контуров — разделите форму на несколько выпуклых частей.
- Большое число динамических тел: подумайте о переходе части логики в события/триггеры вместо физики.
Альтернативные подходы
- Area2D + кастомная логика перекрытий для триггеров (когда не нужно физическое столкновение).
- RayCast2D/ShapeCast2D для предиктивной проверки столкновений на большой скорости.
- Использование пробной симуляции движения через kinematic queries, чтобы предсказывать столкновения до реального перемещения.
Чеклист разработчика перед релизом
- Документированы слои столкновений проекта.
- Включена отладочная визуализация и прогнана сессия тестов.
- Комбинация форм оптимизирована для производительности.
- Специальные случаи (прыжок через угол, скольжение по стене) протестированы.
- Логика удаления/падения предметов не вызывает утечек памяти.
Процесс отладки: runbook
- Включить Visible Collision Shapes.
- Выполнить сценарий, где проявляется баг.
- Посмотреть, пересекаются ли формы или «пролетают» сквозь них.
- Если «пролёт» — добавить ShapeCast2D или raycasts; уменьшить timestep для проверки.
- Если неправильная реакция — проверить нормаль столкновения и порядок обновления velocity.
Ментальные модели и эвристики
- Модель «слой-фильтр»: думайте про коллайдеры как про категории с разрешениями на взаимодействие.
- Модель «первый-уровень/второй-уровень»: сначала грубая AABB-проверка, затем точная физическая проверка.
- Эвристика производительности: простые формы для большого числа объектов, сложные формы только при необходимости.
Решающее дерево для выбора метода
flowchart TD
A[Нужно физическое столкновение?] -->|Да| B{Движение контролируемо}
A -->|Нет| Z[Использовать Area2D или события]
B -->|Да| C{Высокая скорость объекта}
B -->|Нет| D[Использовать move_and_collide/move_and_slide]
C -->|Да| E[Добавить ShapeCast2D или RayCast2D]
C -->|Нет| D
D --> F[Выбрать форму: круг/прямоугольник/комбинация]
F --> G[Назначить слои и маски]
G --> H[Тест и отладка]Короткий глоссарий
- CollisionShape2D — контейнер для формы столкновения.
- CollisionMask/Layer — битовый фильтр взаимодействий.
- Area2D — зона перекрытия, часто используется для триггеров.
- ShapeCast2D — инструмент для предиктивной трассировки формы.
Совместимость и советы по миграции
- Если портируете проект из Godot 3, проверьте соответствие нод KinematicBody2D → CharacterBody2D и обновите вызовы методов движения.
- Перепроверьте экспортированные сцены на предмет устаревших свойств коллайдеров и слоёв.
Заключение
Хорошо спроектированная система столкновений — это синергия правильного выбора форм, продуманной структуры слоёв/масок, сигналов и тестовой методики. Начните с простых форм, документируйте слои и постепенно добавляйте точность там, где это действительно необходимо. Правильная отладка и чеклист помогут избежать распространённых ошибок и обеспечить плавную, предсказуемую механику для игрока.
Ключевые ресурсы: оффлайн документация Godot (локальная справка в редакторе) и официальные туториалы по физике в Godot 4.
Похожие материалы
Как вести протокол собрания
VirtualTourist: советы путешественников и путеводители
Как смотреть несколько часовых поясов на iPhone
MacBook с закрытой крышкой: clamshell — настройка и советы
Spike: почта как рабочее пространство