Гравитация и прыжки
Гравитация
В 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();- койот-тайм и буфер прыжка — два счётчика кадров.