Тема 5 из 6

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

Гравитация

В arcade нет «настоящей» физики для платформера — её пишут сами или берут готовый движок. Основа простая: скорость меняет положение, гравитация меняет скорость.

GRAVITY = 1
MAX_FALL = 12

def on_update(self, delta_time):
    p = self.player
    p.change_y = max(p.change_y - GRAVITY, -MAX_FALL)   # ускоряемся вниз, но не быстрее MAX_FALL
    p.center_y += p.change_y
    if p.bottom < FLOOR:                                 # приземлились
        p.bottom = FLOOR
        p.change_y = 0
  • Прыжок — просто большая скорость вверх: p.change_y = 15. Гравитация сама её погасит и вернёт игрока вниз.
  • Предел скорости падения нужен, чтобы игрок не пролетал сквозь тонкие платформы между кадрами.
  • При приземлении скорость обнуляют — иначе она копится, и следующий прыжок «съедается».

Стены: по одной оси за раз

Чтобы игрок не проходил сквозь стены, его двигают сначала по x, выталкивают из стен, потом по y — и снова выталкивают:

p.center_x += p.change_x
for wall in arcade.check_for_collision_with_list(p, self.walls):
    if p.change_x > 0:
        p.right = wall.left      # шёл вправо — упёрся левым краем стены
    elif p.change_x < 0:
        p.left = wall.right      # шёл влево — упёрся правым краем

p.center_y += p.change_y
for wall in arcade.check_for_collision_with_list(p, self.walls):
    if p.change_y < 0:
        p.bottom = wall.top      # приземлился на платформу
    else:
        p.top = wall.bottom      # ударился головой
    p.change_y = 0

Готовый движок

Всё это уже есть в arcade:

self.engine = arcade.PhysicsEnginePlatformer(self.player, walls=self.walls, gravity_constant=1)

def on_update(self, delta_time):
    self.engine.update()                 # двигает игрока и решает столкновения

def on_key_press(self, symbol, modifiers):
    if symbol == arcade.key.SPACE and self.engine.can_jump():
        self.player.change_y = 15

Движок удобен, но понимать, что у него внутри, полезно: так проще чинить странное поведение и добавлять своё.

Честное управление

Две поблажки, которые есть почти в каждом хорошем платформере:

  • Койот-тайм — прыжок разрешён ещё несколько кадров после схода с края.
  • Буфер прыжка — если нажать пробел чуть раньше приземления, прыжок сработает в момент касания земли.

Для этого хранят два счётчика: сколько кадров назад игрок стоял на земле и сколько кадров назад нажат пробел. Прыжок — когда оба счётчика малы. После прыжка оба «сжигают», чтобы не было второго прыжка в воздухе.

Итог

  • гравитация уменьшает change_y, предел — max(..., -MAX_FALL); при приземлении change_y = 0;
  • двигаем по x — выталкиваем, двигаем по y — выталкиваем;
  • arcade.PhysicsEnginePlatformer, update(), can_jump();
  • койот-тайм и буфер прыжка — два счётчика кадров.