Гравитация и прыжок

Гравитация и прыжок — душа любого платформера. И это снова чистая физика: одно число тянет героя вниз, а прыжок — это толчок вверх.
Суть: гравитация — это постоянное ускорение вниз, прибавляемое к скорости каждый кадр. Прыжок задаёт мгновенную скорость вверх (отрицательную). Земля обнуляет падение.

Если ты когда-нибудь играл в Mario или Celeste, ты чувствовал гравитацию и прыжок интуитивно. Внутри они устроены до смешного просто, и ты уже знаешь все детали из урока про ускорение. Гравитация — это ускорение, направленное вниз. Каждый кадр она прибавляет немного к вертикальной скорости героя. Чем дольше летишь — тем быстрее падаешь.

Прыжок — это разовый толчок: в момент нажатия мы задаём герою отрицательную вертикальную скорость (вверх — это минус Y, помнишь?). Дальше гравитация постепенно гасит этот рывок, скорость из отрицательной становится положительной, и герой начинает падать. Получается красивая параболическая дуга прыжка — и мы не написали ни одной формулы параболы, она возникла сама из гравитации.

Чтобы герой не проваливался сквозь пол, при касании земли мы обнуляем вертикальную скорость и ставим героя ровно на поверхность. И только стоя на земле он может прыгнуть снова — иначе получится бесконечный полёт.

Как работает под капотом

Каждый кадр: скорость по Y растёт на гравитацию, позиция меняется на скорость. Прыжок задаёт стартовую отрицательную скорость. Земля её обнуляет:

   vy при прыжке = -600 (вверх)

   высота
    ^        ___
    |      /     \        гравитация тянет вниз
    |    /         \      каждый кадр: vy += GRAVITY*dt
    |  /             \
    |/                 \___ земля: vy = 0
    +-----------------------> время
    прыжок            падение

В pygame (читаем):

GRAVITY = 1800     # пикс/сек^2
JUMP = -600        # стартовая скорость прыжка (вверх)
vy = 0
on_ground = True

if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
    if on_ground:
        vy = JUMP
        on_ground = False

vy += GRAVITY * dt           # гравитация
player.y += vy * dt
if player.bottom >= GROUND:   # коснулись пола
    player.bottom = GROUND
    vy = 0
    on_ground = True

Всю дугу прыжка можно просчитать без графики — это та самая физика. Запусти и посмотри, как герой взлетает и падает обратно. Попробуй сам:

GRAVITY = 1800.0
JUMP = -600.0
GROUND = 0.0       # уровень земли по высоте
dt = 0.05

y = 0.0
vy = JUMP          # прыгнули

for step in range(14):
    vy += GRAVITY * dt        # гравитация
    y += vy * dt              # двигаем (y вниз положительный)
    if y >= GROUND and vy > 0: # приземлились
        y = GROUND
        vy = 0.0
        print(f"шаг {step+1:2}: ПРИЗЕМЛИЛСЯ")
        break
    print(f"шаг {step+1:2}: высота={-y:6.1f}  vy={vy:7.1f}")

Приёмы хорошего прыжка

Идеальный игровой прыжок — это не голая физика, а набор маленьких уловок, делающих его приятным. Первая — «время койота» (coyote time): если игрок шагнул с края платформы и нажал прыжок на пару кадров позже, мы всё равно разрешаем прыгнуть. Это прощает крошечные опоздания и убирает ощущение «я же нажал!». Вторая — буфер прыжка: если игрок нажал прыжок чуть раньше приземления, мы запоминаем нажатие и выполняем его сразу, как коснулись земли.

Третья уловка — переменная высота прыжка: если игрок отпустил кнопку рано, мы гасим часть скорости вверх, и прыжок выходит низким; держит дольше — прыгает выше. Так один и тот же прыжок даёт и аккуратный подскок, и мощный взлёт. Все эти приёмы — это просто пара дополнительных таймеров и условий поверх той же гравитации, что ты уже понимаешь. Именно они отличают «работающий прыжок» от прыжка, который ощущается отзывчивым и честным, как в любимых платформерах.

Частые ошибки

  • Задавать прыжку положительную скорость — герой «прыгнет» вниз, ведь вверх это минус Y.
  • Не проверять on_ground — герой прыгает в воздухе бесконечно.
  • Забыть обнулить vy на земле — скорость падения копится, и в следующий раз герой проваливается сквозь пол.

Best practices

  • Гравитацию прибавляй к скорости, скорость — к позиции (та же двухступенчатая цепочка).
  • Разреши прыжок только при on_ground; для двойного прыжка — счётчик прыжков.
  • При приземлении ставь героя ровно на пол через rect.bottom.

Итог: гравитация — постоянное ускорение вниз, прыжок — стартовый рывок вверх, земля — обнуление. Из этих трёх правил рождается живая дуга прыжка.

Проверьте себя
1. Какой знак у стартовой вертикальной скорости в момент прыжка?
AПоложительный — вверх
BОтрицательный — потому что вверх это минус Y
CВсегда ноль
DЗависит от FPS
2. Зачем проверять флаг on_ground перед прыжком?
AДля красоты кода
BЧтобы герой не прыгал бесконечно в воздухе
CЧтобы ускорить игру
DЧтобы включить звук