</>
Тема 4 из 6

Столкновения

В любой игре нужно понимать, что с чем столкнулось: игрок с монетой, пуля с врагом, мяч со стеной, курсор с кнопкой. В pygame это делает Rect.

Точка и прямоугольник

button = pygame.Rect(100, 50, 200, 60)
print(button.collidepoint(150, 80))    # True — точка внутри
print(button.collidepoint((300, 80)))  # False — x = 300 уже снаружи

Прямоугольник (x, y, w, h) содержит точки с x от x до x + w - 1 и y от y до y + h - 1. Значит, right и bottom — это первая координата за прямоугольником. Это частый источник ошибок «на один пиксель», если сравнивать вручную.

Клик мышью — событие MOUSEBUTTONDOWN с полем event.pos, а текущее положение курсора — pygame.mouse.get_pos().

Два прямоугольника

player.colliderect(coin)     # пересекаются ли
player.contains(coin)        # лежит ли coin целиком внутри player

Прямоугольники, которые только касаются сторонами, не пересекаются.

Один со многими

i = player.collidelist(coins)          # номер первой монеты, которой касается игрок, или -1
hits = player.collidelistall(coins)    # номера всех таких монет

Удаление из списка

Собранные монеты нужно убрать, но удалять из списка внутри цикла по нему нельзя — цикл перескочит через элемент:

for coin in coins:              # ошибка: после remove следующая монета пропускается
    if player.colliderect(coin):
        coins.remove(coin)

Правильно — построить новый список тех, что остаются:

coins[:] = [c for c in coins if not player.colliderect(c)]

Запись coins[:] = … меняет тот же список, который передали в функцию. А coins = […] внутри функции создаст новый список только в ней — снаружи монеты не исчезнут.

Отскок

Отскок — это смена знака скорости. Но если просто писать vx = -vx, мяч, оказавшийся за стеной (быстро влетел или его там подали), будет каждый кадр менять направление и «дрожать». Надёжнее задавать направление явно:

if ball.left <= field.left:
    vx = abs(vx)       # от левой стены — всегда вправо
if ball.right >= field.right:
    vx = -abs(vx)      # от правой — всегда влево

То же для ракетки: отражать мяч, только если он летит к ней (vy > 0), иначе он «застрянет» внутри.

Итог

  • collidepoint — точка, colliderect — прямоугольник; right и bottom уже снаружи;
  • collidelist — первый, collidelistall — все;
  • не удаляйте из списка в цикле по нему; lst[:] = … меняет переданный список;
  • отскок: задавайте направление через abs, а не переворачивайте знак.