"""Player movement & collision.""" from conftest import step, run, place, hold from game import settings as S FLAT = """ name: t tile_size: 32 map: | ########## #........# #........# #........# #P......G# ########## """ def test_falls_and_lands_on_floor(make_game): g = make_game(FLAT) place(g, 4, 1) # up in the air run(g, 60) assert g.player.on_ground assert g.player.rect.bottom == 5 * 32 # floor is row 5's top (y=160) def test_terminal_velocity(make_game): g = make_game(FLAT) place(g, 4, 1) for _ in range(200): step(g) assert g.player.vy <= S.MAX_FALL + 1 def test_jump_gains_height_then_returns(make_game): g = make_game(FLAT) run(g, 30) # settle on floor ground = g.player.rect.bottom peak = ground for i in range(60): step(g, hold(jump_pressed=(i == 0), jump_held=True)) peak = min(peak, g.player.rect.bottom) assert peak < ground - 32 # rose at least a tile def test_variable_jump_height(make_game): # Full-hold jump should out-climb a 1-frame tap. def peak(hold_frames): g = make_game(FLAT) run(g, 30) ground = g.player.rect.bottom hi = ground for i in range(60): held = i < hold_frames step(g, hold(jump_pressed=(i == 0), jump_held=held)) hi = min(hi, g.player.rect.bottom) return ground - hi assert peak(60) > peak(1) + 8 def test_coyote_time_allows_jump_after_leaving_ledge(make_game): # Walk off a ledge, then jump within the coyote window -> should rise. g = make_game(""" name: t tile_size: 32 map: | ####### #.....# #.....# ##....# #P#...# ####### """) place(g, 1, 3) # standing on the little step at [1,3] top # walk right off the step for a couple frames, then jump run(g, 4, lambda i: hold(right=True)) y_before = g.player.rect.bottom step(g, hold(right=True, jump_pressed=True, jump_held=True)) step(g, hold(right=True, jump_held=True)) assert g.player.vy < 0 # a jump actually started def test_walls_stop_horizontal_movement(make_game): g = make_game(FLAT) place(g, 1, 4) run(g, 120, lambda i: hold(right=True)) assert g.player.rect.right <= 9 * 32 # right wall inner edge (x=288) run(g, 120, lambda i: hold(left=True)) assert g.player.rect.left >= 1 * 32 # left wall inner edge (x=32) def test_oneway_platform_land_from_above_pass_from_below(make_game): g = make_game(""" name: t tile_size: 32 map: | ####### #.....# #.....# #--...# #.....# #P...G# ####### """) # Fall onto the one-way from above -> lands on it. place(g, 1, 1) # open air above the one-way (row 3) run(g, 60) assert g.player.on_ground and g.player.rect.bottom == 3 * 32 # From below, jumping up passes through it (doesn't block the head). g2 = make_game(""" name: t tile_size: 32 map: | ####### #.....# #--...# #.....# #P...G# ####### """) place(g2, 1, 4) # on the floor, below the one-way (row 2) run(g2, 5) # settle so on_ground is set before jumping passed = False for i in range(40): step(g2, hold(jump_pressed=(i == 0), jump_held=(i < 12))) if g2.player.rect.top < 2 * 32: # rose above the one-way row passed = True assert passed def test_drop_through_oneway(make_game): g = make_game(""" name: t tile_size: 32 map: | ####### #.....# #.....# #--...# #.....# #....G# ####### """) place(g, 1, 2) # standing on the one-way at row 3 run(g, 20) assert g.player.on_ground # press down + jump to drop through for i in range(30): step(g, hold(down=True, jump_pressed=(i == 0))) assert g.player.rect.top > 3 * 32 # fell below the one-way