Menu
CoddyTech

Choque

Parte de la sección Reglas del juego del Journey de Pygame de Coddy. Lección 27 de 29.

Tocar un obstáculo termina la partida. pygame.sprite.spritecollideany(sprite, group) devuelve el primer sprite del grupo que toca al sprite, o None.

De forma predeterminada, compara los rectángulos. Las imágenes tienen las esquinas transparentes, sobre todo la masa, así que dos rectángulos pueden superponerse aunque nada de lo que ves se toque. Un tercer argumento elige una prueba más justa:

if pygame.sprite.spritecollideany(runner, obstacles, pygame.sprite.collide_mask):
    state = "over"

collide_mask compara los píxeles dibujados de las imágenes e ignora los transparentes. Así, un choque es algo que el jugador puede ver.

El estado funciona igual que en Meteor Dodge: la actualización, los saltos y los nuevos obstáculos ocurren solo mientras está en "play", y la pantalla de fin de partida dibuja el juego congelado con un mensaje.

challenge icon

Desafío

Intermedio
  1. Añade una fuente, assets/fonts/pixel.ttf de tamaño 32, y state = "play".
  2. Solo mientras el estado sea "play": salta, añade obstáculos, actualiza al corredor y los obstáculos.
  3. Cuando el corredor toque un obstáculo (collide_mask), establece el estado en "over".
  4. Cuando termine el juego, muestra Game over en (40, 50, 80) centrado en (320, 140).

Pruébalo tú mismo

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 320))
pygame.display.set_caption("Sky Runner")
clock = pygame.time.Clock()

SKY = (140, 200, 240)
GROUND = (90, 160, 80)
GROUND_Y = 260
GRAVITY = 1
SPAWN = pygame.USEREVENT + 1


class Runner(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.frames = [
            pygame.image.load("assets/images/player.png").convert_alpha(),
            pygame.image.load("assets/images/player_walk.png").convert_alpha(),
        ]
        self.image = self.frames[0]
        self.step = 0
        self.rect = self.image.get_rect(midbottom=(100, GROUND_Y))
        self.vy = 0

    def jump(self):
        if self.rect.bottom == GROUND_Y:
            self.vy = -16

    def update(self):
        self.vy += GRAVITY
        self.rect.y += self.vy
        if self.rect.bottom >= GROUND_Y:
            self.rect.bottom = GROUND_Y
            self.vy = 0
        if self.rect.bottom == GROUND_Y:
            self.step += 1
            self.image = self.frames[self.step // 8 % 2]
        else:
            self.image = self.frames[1]


class Obstacle(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = random.choice(obstacle_images)
        self.rect = self.image.get_rect(midbottom=(664, GROUND_Y))

    def update(self):
        self.rect.x -= speed
        if self.rect.right < 0:
            self.kill()


obstacle_images = [
    pygame.image.load("assets/images/spike_ball.png").convert_alpha(),
    pygame.image.load("assets/images/blob.png").convert_alpha(),
]
runner = Runner()
obstacles = pygame.sprite.Group()
speed = 6
pygame.time.set_timer(SPAWN, 1500)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
            runner.jump()
        if event.type == SPAWN:
            obstacles.add(Obstacle())
            pygame.time.set_timer(SPAWN, random.randint(1000, 2000))

    runner.update()
    obstacles.update()

    screen.fill(SKY)
    pygame.draw.rect(screen, GROUND, (0, GROUND_Y, 640, 60))
    screen.blit(runner.image, runner.rect)
    obstacles.draw(screen)
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Todas las lecciones de Reglas del juego

Practica por tu cuenta: Playground de Pygame