Rect и движение
Всё, что движется в игре, удобно описывать прямоугольником pygame.Rect: игрок, пуля, платформа, кнопка. Он хранит положение и размер и умеет сдвигаться, проверять пересечения и не выходить за границы.
Rect
import pygame
r = pygame.Rect(10, 20, 30, 40) # x, y, ширина, высота
print(r.x, r.y, r.w, r.h) # 10 20 30 40
print(r.right, r.bottom) # 40 60 (x + w, y + h)
print(r.center, r.topleft) # (25, 40) (10, 20)
У прямоугольника много «ручек»: left, right, top, bottom, centerx, centery, center, topleft, midbottom… Их можно не только читать, но и присваивать — прямоугольник сдвинется целиком, размер не изменится:
r.bottom = 100 # теперь нижняя сторона на 100, а y = 60
r.center = (0, 0) # центр в начале координат
Это удобнее, чем пересчитывать x и y вручную: «поставить на землю» — это r.bottom = GROUND, а не r.y = GROUND - r.h.
Координаты у Rect — целые числа: дробная часть отбрасывается.
Движение
Движение в игре — это изменение координат каждый кадр:
r.x += 5 # на 5 пикселей вправо за кадр
r.move_ip(5, -2) # сразу по двум осям
r2 = r.move(5, -2) # новый прямоугольник, r не меняется
При 60 кадрах в секунду скорость 5 пикселей за кадр — это 300 пикселей в секунду.
Не выйти за экран
field = screen.get_rect() # Rect(0, 0, ширина, высота)
r.clamp_ip(field) # сдвинуть r внутрь field, если он вылез
print(field.contains(r)) # True, если r целиком внутри
clamp_ip прижимает прямоугольник к ближайшему краю — по обеим осям сразу. Писать это вручную легко с ошибкой: забыть ось, сравнить не ту сторону, ошибиться на один пиксель.
Гравитация и прыжок
Чтобы движение выглядело естественно, у объекта хранят скорость и меняют её каждый кадр:
vy += GRAVITY # гравитация разгоняет вниз
player.y += vy # двигаем на текущую скорость
if player.bottom >= GROUND: # коснулись земли
player.bottom = GROUND # ставим ровно на землю
vy = 0
Прыжок — это просто отрицательная скорость: vy = -15. Дальше гравитация сама замедлит подъём и вернёт персонажа вниз. Прыгать можно только с земли — иначе получится «полёт».
Перенос через край
В аркадах объект, ушедший за край, часто появляется с другой стороны. Важно решить, когда переносить (когда коснулся края или когда скрылся целиком) и куда ставить (чтобы он плавно въехал, а не возник целиком).
Итог
pygame.Rect(x, y, w, h):right,bottom,center… — читать и присваивать;move_ip(dx, dy)— сдвинуть на месте,move— получить сдвинутую копию;clamp_ip(field)— оставить внутри поля;- скорость и гравитация:
vy += GRAVITY; y += vy, приземление —bottom = GROUND; vy = 0.