Menu
CoddyTech

Un axe à la fois

Fait partie de la section Les mondes du Journey Pygame de Coddy. Leçon 19 sur 35.

Votre code de collision déplace le joueur et corrige sa position sur l’axe x, puis le déplace et corrige sa position sur l’axe y. Ce code de départ déplace le joueur sur les deux axes et ne corrige sa position qu’une seule fois. Exécutez-le et avancez vers la droite : le joueur recule brusquement le long du sol.

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

Debout sur le sol, la gravité déplace le joueur d’un pixel vers le bas, dans le sol, à chaque image. En avançant vers la droite pendant la même image, le joueur chevauche la tuile de sol située en dessous, et le code ne peut pas savoir pourquoi. Il voit dx > 0 et place le côté droit du joueur au niveau du côté gauche de cette tuile : vers l’arrière, le long du sol.

Un chevauchement, deux déplacements, impossible de savoir lequel l’a provoqué. En ne traitant qu’un seul axe à la fois, chaque chevauchement a une seule cause. Après le déplacement sur l’axe x, le joueur n’est pas encore dans le sol ; seuls les vrais murs l’arrêtent donc. Après le déplacement sur l’axe y, le chevauchement ne peut venir que d’un déplacement sur l’axe y.

challenge icon

Défi

Moyen
  1. Sépare le mouvement : player.x += dx et une boucle sur walls qui ne corrige que x.
  2. Ensuite, la gravité, player.y += vel_y, on_ground = False et une deuxième boucle qui ne corrige que y.

Essayez vous-même

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

Toutes les leçons de Les mondes

Entraînez-vous par vous-même : Playground Pygame