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