Menu
CoddyTech

Un eje a la vez

Parte de la sección Mundos del Journey de Pygame de Coddy. Lección 19 de 35.

Tu código de colisiones mueve y corrige x, y después mueve y corrige y. Este ejemplo inicial mueve ambos ejes y corrige solo una vez. Ejecútalo y camina hacia la derecha: el jugador retrocede de golpe por el suelo.

player.x += dx
vel_y = min(vel_y + GRAVITY, MAX_FALL)
player.y += vel_y
on_ground = False
for wall in walls:
    if player.colliderect(wall):
        if dx > 0:
            player.right = wall.left
        elif dx < 0:
            player.left = wall.right
        if vel_y > 0:
            player.bottom = wall.top
            on_ground = True
        elif vel_y < 0:
            player.top = wall.bottom
        vel_y = 0

Al estar de pie en el suelo, la gravedad mueve al jugador 1 píxel hacia abajo, dentro del suelo, cada fotograma. Si se mueve hacia la derecha en el mismo fotograma, el jugador se superpone con la baldosa del suelo que tiene debajo, y el código no puede saber por qué. Ve dx > 0 y coloca el lado derecho del jugador junto al lado izquierdo de esa baldosa: hacia atrás, por el suelo.

Una superposición, dos movimientos, ninguna forma de saber cuál la causó. Si se mueve un eje a la vez, cada superposición tiene una sola causa. Después del movimiento en x, el jugador todavía no está dentro del suelo, así que solo las paredes reales lo detienen. Después del movimiento en y, la superposición solo puede deberse al movimiento a lo largo del eje y.

challenge icon

Desafío

Intermedio
  1. Separa el movimiento: player.x += dx y un bucle sobre walls que corrige solo x.
  2. Después, la gravedad, player.y += vel_y, on_ground = False y un segundo bucle que corrige solo y.

Pruébalo tú mismo

import pygame

TILE = 36
SPEED = 4
GRAVITY = 1
JUMP = -15
MAX_FALL = 12

LEVEL = [
    "................",
    "................",
    "................",
    "....P.....###...",
    "................",
    "................",
    "...####.........",
    "............#...",
    "#.......#...#..#",
    "################",
]

pygame.init()
screen = pygame.display.set_mode((576, 360))
pygame.display.set_caption("One Axis at a Time")
clock = pygame.time.Clock()

background = pygame.image.load("assets/backgrounds/clouds.png").convert_alpha()
block_img = pygame.image.load("assets/images/block.png").convert_alpha()
player_img = pygame.image.load("assets/images/player.png").convert_alpha()

walls = []
for row, line in enumerate(LEVEL):
    for col, char in enumerate(line):
        if char == "#":
            walls.append(pygame.Rect(col * TILE, row * TILE, TILE, TILE))
        elif char == "P":
            start = (col * TILE + TILE // 2, row * TILE + TILE)

player = player_img.get_rect(midbottom=start)
vel_y = 0
on_ground = False

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
            if on_ground:
                vel_y = JUMP
        elif event.type == pygame.KEYUP and event.key in (pygame.K_SPACE, pygame.K_UP):
            if vel_y < -4:
                vel_y = -4

    keys = pygame.key.get_pressed()
    dx = 0
    if keys[pygame.K_LEFT]:
        dx -= SPEED
    if keys[pygame.K_RIGHT]:
        dx += SPEED

    player.x += dx
    vel_y = min(vel_y + GRAVITY, MAX_FALL)
    player.y += vel_y
    on_ground = False
    for wall in walls:
        if player.colliderect(wall):
            if dx > 0:
                player.right = wall.left
            elif dx < 0:
                player.left = wall.right
            if vel_y > 0:
                player.bottom = wall.top
                on_ground = True
            elif vel_y < 0:
                player.top = wall.bottom
            vel_y = 0

    for y in range(0, 360, 72):
        for x in range(0, 576, 72):
            screen.blit(background, (x, y))
    for wall in walls:
        screen.blit(block_img, wall)
    screen.blit(player_img, player)
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Todas las lecciones de Mundos

Practica por tu cuenta: Playground de Pygame