Menu
CoddyTech

Collision

Fait partie de la section Règles du jeu du Journey Pygame de Coddy. Leçon 27 sur 29.

Toucher un obstacle met fin à la partie. pygame.sprite.spritecollideany(sprite, group) renvoie le premier sprite du groupe qui touche le sprite, ou None.

Par défaut, la fonction compare les rectangles. Les images ont des coins transparents, surtout celle de la blob, donc deux rectangles peuvent se chevaucher alors que rien de ce que tu vois ne se touche. Un troisième argument permet de choisir un test plus équitable :

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

collide_mask compare les pixels dessinés des images et ignore les pixels transparents. Un crash est alors un crash que le joueur peut voir.

L’état fonctionne comme dans Meteor Dodge : la mise à jour, les sauts et l’apparition de nouveaux obstacles n’ont lieu que lorsque l’état est "play", et l’écran de fin de partie affiche le jeu figé avec un message.

challenge icon

Défi

Moyen
  1. Ajoute une police, assets/fonts/pixel.ttf de taille 32, et state = "play".
  2. Uniquement lorsque l’état est "play" : fais sauter le personnage, ajoute des obstacles et mets à jour le personnage et les obstacles.
  3. Lorsque le personnage touche un obstacle (collide_mask), définis l’état sur "over".
  4. Lorsque la partie est terminée, affiche Game over en (40, 50, 80), centré en (320, 140).

Essayez vous-même

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

Toutes les leçons de Règles du jeu

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