Menu
CoddyTech

Un asse alla volta

Fa parte della sezione Mondi del percorso Pygame di Coddy. Lezione 19 di 35.

Il tuo codice di collisione sposta e corregge x, poi sposta e corregge y. Questo codice iniziale sposta entrambi gli assi e corregge una sola volta. Eseguilo e cammina verso destra: il personaggio scatta all'indietro lungo il pavimento.

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

Quando è fermo a terra, la gravità sposta il personaggio di 1 pixel verso il basso, dentro il terreno, a ogni fotogramma. Spostandosi verso destra nello stesso fotogramma, il personaggio si sovrappone alla tessera del terreno sottostante e il codice non riesce a capire perché. Rileva dx > 0 e posiziona il lato destro del personaggio sul lato sinistro di quella tessera: all'indietro, lungo il pavimento.

Una sovrapposizione, due movimenti, nessun modo per sapere quale movimento l'ha causata. Muovendo un asse alla volta, ogni sovrapposizione ha una sola causa. Dopo il movimento lungo x, il personaggio non è ancora dentro il terreno, quindi solo i muri effettivi lo fermano. Dopo il movimento lungo y, la sovrapposizione può dipendere solo dal movimento lungo y.

challenge icon

Sfida

Medio
  1. Separa il movimento: player.x += dx e un ciclo su walls che corregge solo x.
  2. Poi la gravità, player.y += vel_y, on_ground = False e un secondo ciclo che corregge solo y.

Provalo tu

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()

Tutte le lezioni di Mondi

Esercitati da solo: Playground Pygame