Menu
CoddyTech

Eine Achse nach der anderen

Teil des Abschnitts Spielwelten der Pygame-Journey von Coddy. Lektion 19 von 35.

Dein Kollisionscode bewegt und korrigiert zuerst x und dann y. Dieser Ausgangscode bewegt beide Achsen und korrigiert nur einmal. Führe ihn aus und gehe nach rechts: Der Spieler wird auf dem Boden rückwärts versetzt.

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

Wenn der Spieler auf dem Boden steht, bewegt die Schwerkraft ihn in jedem Frame 1 Pixel nach unten in den Boden. Bewegt er sich im selben Frame nach rechts, überlappt der Spieler die Bodenkachel unter ihm, und der Code kann nicht erkennen, warum. Er sieht dx > 0 und setzt die rechte Seite des Spielers an die linke Seite dieser Kachel: rückwärts, entlang des Bodens.

Eine Überlappung, zwei Bewegungen, keine Möglichkeit zu erkennen, welche Bewegung sie verursacht hat. Bewegt man jeweils nur eine Achse, hat jede Überlappung eine einzige Ursache. Nach der Bewegung entlang der x-Achse ist der Spieler noch nicht im Boden, sodass ihn nur echte Wände aufhalten. Nach der Bewegung entlang der y-Achse kann die Überlappung nur durch die Bewegung entlang der y-Achse entstehen.

challenge icon

Aufgabe

Mittel
  1. Teile die Bewegung auf: player.x += dx und eine Schleife über walls, die nur x korrigiert.
  2. Dann die Schwerkraft, player.y += vel_y, on_ground = False und eine zweite Schleife, die nur y korrigiert.

Probier es selbst

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

Alle Lektionen in Spielwelten

Übe selbstständig: Pygame-Playground