Гравитация и прыжок: платформер
Платформер отличается от топ-дауна тем, что вниз всегда тянет гравитация, а вверх — короткий импульс прыжка.
Суть: каждый кадр прибавляй гравитацию к velocity.y, а при прыжке задавай velocity.y большим отрицательным числом (вверх — это минус).
В платформере персонаж бегает влево-вправо и прыгает, а земля держит его снизу. Чтобы это работало, нужны две вещи: постоянная сила вниз (гравитация) и кратковременный толчок вверх (прыжок). Помни про ось y в 2D: вниз — это плюс, вверх — это минус. Поэтому гравитация прибавляется к velocity.y, а прыжок задаёт velocity.y большим отрицательным значением.
extends CharacterBody2D
@export var speed: float = 250.0
@export var jump_force: float = 400.0
@export var gravity: float = 980.0
func _physics_process(delta: float) -> void:
# Гравитация тянет вниз, пока мы не на полу
if not is_on_floor():
velocity.y += gravity * delta
# Прыжок только с земли
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = -jump_force
# Горизонтальное движение
var dir: float = Input.get_axis("move_left", "move_right")
velocity.x = dir * speed
move_and_slide()Ключевая функция здесь — is_on_floor(): CharacterBody2D сам понимает, стоит ли он на земле, после move_and_slide. Прыгать можно только с пола, иначе получится бесконечный полёт. А прыжок — это is_action_just_pressed (один раз в момент нажатия), не is_action_pressed, иначе при удержании персонаж залипнет в воздухе.
Стоит почувствовать, как параметры влияют на ощущение от прыжка. Большая jump_force и маленькая gravity дают «лунный», парящий прыжок; маленькая сила и сильная гравитация — резкий, цепкий. Профессионалы подбирают эти числа неделями, ведь именно от них зависит, приятно ли управлять героем. Поэтому так удобно держать gravity, jump_force и speed в @export: ты меняешь одно число, тут же запускаешь игру и чувствуешь разницу. Хороший платформер начинается не с графики, а с того, что прыжок просто приятно повторять снова и снова.
Как работает под капотом
Гравитация — это постоянное ускорение. Каждый кадр мы прибавляем к вертикальной скорости небольшую порцию (gravity * delta), и скорость падения растёт: персонаж разгоняется вниз, как настоящий предмет. Прыжок мгновенно задаёт большую скорость вверх; затем гравитация постепенно её гасит, разворачивает и тянет обратно — получается красивая дуга прыжка.
gravity = 980.0
jump_force = 400.0
vy = -jump_force # оттолкнулись вверх (минус = вверх)
y = 0.0
delta = 1 / 30
for frame in range(1, 11):
vy += gravity * delta # гравитация добавляет скорость вниз
y += vy * delta
spot = "вверх" if vy < 0 else "вниз"
print(f"Кадр {frame:2}: высота {-y:6.1f}, летим {spot}")
print("Скорость прошла через 0 — это вершина прыжка.")Та же логика на Python ▶. Скорость стартует отрицательной (вверх), гравитация её увеличивает, она проходит через ноль (вершина дуги) и становится положительной (падение). Так рождается дуга прыжка.
Частые ошибки
Первая ошибка — задать прыжок положительным числом: velocity.y = jump_force отправит персонажа в землю, ведь вниз это плюс. Прыжок — это минус. Вторая — использовать is_action_pressed вместо is_action_just_pressed для прыжка: при удержании клавиши скорость каждый кадр сбрасывается вверх, и персонаж зависает. Третья — прибавлять гравитацию даже на полу: если не проверять is_on_floor(), скорость вниз копится, и is_on_floor может сбоить; обычно гравитацию добавляют только в воздухе. Четвёртая — забыть, что без коллизий под ногами is_on_floor всегда ложно и герой падает вечно.
Best practices
Выноси gravity, jump_force и speed в @export — баланс прыжка подбирается на ощупь, и крутить его из инспектора удобно. Используй is_on_floor() и для прыжка, и для гравитации. Бери is_action_just_pressed для прыжка. Для горизонтали в платформере удобен Input.get_axis (одно число от -1 до 1), а не get_vector. И помни главное правило 2D-вертикали: вверх — минус, вниз — плюс.
Итоги: платформер = гравитация вниз каждый кадр (velocity.y += gravity * delta) + прыжок вверх по нажатию (velocity.y = -jump_force). is_on_floor() говорит, на земле ли мы. Прыжок — только с пола и через is_action_just_pressed. Вверх — это минус по y. Дуга прыжка получается сама из гравитации.