AABB: столкновение прямоугольников
Как игра понимает, что герой коснулся монетки или врага? Через коллизии. И самый частый их вид — AABB, проверка пересечения прямоугольников.
Суть: AABB-коллизия проверяет, перекрываются ли два прямоугольника по обеим осям. Если по X есть нахлёст И по Y есть нахлёст — объекты столкнулись.
Коллизия (столкновение) — это сердце игрового взаимодействия. Собрал монетку, получил урон, отскочил от стены, попал пулей — всё это коллизии. Самый распространённый и быстрый способ их проверять называется AABB: Axis-Aligned Bounding Box, «ограничивающий прямоугольник, выровненный по осям». Звучит грозно, а внутри — простейшая логика.
Каждый объект оборачиваем в прямоугольник. Два прямоугольника пересекаются тогда и только тогда, когда они перекрываются ОДНОВРЕМЕННО по горизонтали и по вертикали. Если они нахлёстываются по X, но один выше другого (по Y нет нахлёста) — столкновения нет. И наоборот. Только когда обе оси «согласны», объекты действительно касаются.
В Pygame это уже готово: rect_a.colliderect(rect_b) возвращает True при пересечении. Но понять формулу важно — она объясняет, почему иногда коллизии «не срабатывают», и лежит в основе физики платформеров.
Как работает под капотом
Проверка идёт по каждой оси отдельно. По X объекты пересекаются, если левый край одного левее правого края другого И наоборот. То же по Y. Столкновение = пересечение по X И по Y:
нет нахлёста по Y -> НЕТ коллизии
+----+
| A |
+----+
+----+
| B |
+----+
нахлёст по X И по Y -> ЕСТЬ коллизия
+------+
| A +--+---+
+---+--+ B |
+------+
условие: A.left < B.right И A.right > B.left
И A.top < B.bottom И A.bottom > B.top
В pygame (читаем):
player = pygame.Rect(100, 100, 50, 50)
coin = pygame.Rect(130, 120, 20, 20)
if player.colliderect(coin):
score += 1
coin_sprite.kill()Реализуем AABB своими руками — это та самая формула, что внутри colliderect. Запусти и проверь на разных прямоугольниках. Попробуй сам:
def aabb(a, b):
ax, ay, aw, ah = a
bx, by, bw, bh = b
return (ax < bx + bw and ax + aw > bx and
ay < by + bh and ay + ah > by)
player = (100, 100, 50, 50)
tests = {
"монетка рядом": (130, 120, 20, 20),
"монетка ниже": (130, 200, 20, 20),
"касание углом": (149, 149, 20, 20),
}
for name, other in tests.items():
print(f"{name}: столкновение = {aabb(player, other)}")Когда AABB не подходит
AABB идеален для прямоугольных и почти прямоугольных объектов, но у него есть слабое место — он не знает о форме спрайта, только о его прямоугольной рамке. Для круглого мячика или диагонального меча прямоугольная рамка будет «толще» картинки, и попадания засчитаются в пустоту по углам. Для кругов точнее проверка по расстоянию между центрами (сравнить его с суммой радиусов), а для сложных форм — попиксельная маска pygame.mask, которая сверяет реальные непрозрачные пиксели.
Но не спеши усложнять. В подавляющем большинстве 2D-игр AABB более чем достаточно, а маски заметно медленнее. Опытные разработчики применяют двухступенчатый приём: сначала быстрая грубая AABB-проверка отсеивает заведомо далёкие пары, и только для оставшихся «подозрительных» запускают дорогую точную проверку маской. Так игра остаётся и быстрой, и точной. Начинай всегда с AABB, а к маскам переходи лишь там, где точность реально важна и игрок замечает разницу.
Полезно понимать, почему AABB так популярен, несмотря на грубость. Причина — скорость: проверка сводится к четырём сравнениям чисел, без единого умножения или корня, поэтому её можно прогонять для тысяч пар объектов каждый кадр без просадки FPS. В играх, где важнее быстро отсеять заведомо далёкие объекты, чем идеально точно поймать касание угла, это решающее преимущество. Добавь к этому, что прямоугольник естественно описывает большинство игровых объектов — платформы, ящики, экранные кнопки, зоны, — и станет понятно, почему AABB лежит в фундаменте почти любой 2D-игры. Это тот случай, когда «достаточно хорошо и очень быстро» побеждает «идеально, но медленно».
Частые ошибки
- Проверять только одну ось — получишь «коллизию» там, где объекты разнесены по другой оси.
- Использовать <= вместо < — объекты, касающиеся ровно краями, будут считаться столкнувшимися (иногда это нежелательно).
- Забыть обновить rect перед проверкой — проверяешь старую позицию.
Best practices
- Для прямоугольных объектов используй встроенный
colliderect— он быстрый и проверенный. - Делай хитбокс чуть меньше спрайта — игроку приятнее, когда «почти попал» не считается попаданием.
- Понимай формулу: она пригодится для разрешения столкновений в платформере.
Итог: AABB — это проверка нахлёста по X И по Y. Простая формула, на которой держится почти вся 2D-физика.