Créer un jeu de labyrinthe avec Pygame

PythonPythonBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce projet, nous allons créer un jeu de labyrinthe à l'aide de la bibliothèque Pygame en Python. Le jeu consiste à faire naviguer un joueur dans un labyrinthe pour ramasser des objets de nourriture tout en évitant les murs. Nous allons diviser le processus de développement en plusieurs étapes pour le rendre plus facile à comprendre et à suivre.

👀 Aperçu

Capture d'écran d'aperçu du jeu de labyrinthe

🎯 Tâches

Dans ce projet, vous allez apprendre :

  • Comment configurer l'environnement du jeu à l'aide de Pygame
  • Comment créer le labyrinthe à l'aide de cellules et de murs
  • Comment ajouter des objets de nourriture pour que le joueur puisse les ramasser
  • Comment implémenter le mouvement du joueur et la détection de collisions
  • Comment gérer la logique du jeu, y compris le calcul du score et les conditions de fin de partie
  • Comment suivre le record du joueur
  • Comment afficher des statistiques de jeu telles que le temps, le score et le record à l'écran

🏆 Réalisations

Après avoir terminé ce projet, vous serez capable de :

  • Utiliser la bibliothèque Pygame pour le développement de jeux
  • Appliquer les concepts de programmation orientée objet pour créer des éléments de jeu
  • Monter en évidence votre capacité à penser algorithmiquement et à résoudre des problèmes pour la génération de labyrinthes
  • Gérer le traitement des événements et l'entrée du joueur
  • Implémenter la détection de collisions et les mécanismes de mouvement dans un environnement de jeu
  • Gérer la manipulation de fichiers pour stocker et récupérer les records de jeu
  • Afficher des statistiques et des informations de jeu à l'écran

Configuration de l'environnement

Tout d'abord, nous allons créer les fichiers du projet pour le jeu de labyrinthe.

cd ~/projet
touch maze.py
sudo pip install pygame

Dans cette étape, nous allons configurer l'environnement Pygame et définir des constantes.

import pygame
from random import choice, randrange

## Constantes pour les dimensions de l'écran et la taille des tuiles
RES = LARGEUR, HAUTEUR = 1202, 902
CARREAU = 100
cols, rows = LARGEUR // CARREAU, HAUTEUR // CARREAU

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous importons les bibliothèques nécessaires (Pygame et random).
  • Nous définissons des constantes pour les dimensions de l'écran et la taille des tuiles.
  • Pygame est initialisé et la fenêtre de jeu est configurée.
  • Nous chargeons les images d'arrière-plan pour le jeu.
✨ Vérifier la solution et pratiquer

Création de la classe Cellule

Dans cette étape, nous allons définir la classe Cell pour représenter les cellules du labyrinthe.

## Définissez une classe pour représenter les cellules dans le labyrinthe
class Cell:
    def __init__(self, x, y):
        self.x, self.y = x, y
        ## Les murs représentent les limites de la cellule
        self.walls = {"top": True, "right": True, "bottom": True, "left": True}
        self.visited = False
        self.thickness = 4

    ## Dessinez les murs de la cellule
    def draw(self, sc):
        x, y = self.x * TILE, self.y * TILE
        if self.walls["top"]:
            pygame.draw.line(
                sc, pygame.Color("darkorange"), (x, y), (x + TILE, y), self.thickness
            )
        if self.walls["right"]:
            pygame.draw.line(
                sc,
                pygame.Color("darkorange"),
                (x + TILE, y),
                (x + TILE, y + TILE),
                self.thickness,
            )
        if self.walls["bottom"]:
            pygame.draw.line(
                sc,
                pygame.Color("darkorange"),
                (x + TILE, y + TILE),
                (x, y + TILE),
                self.thickness,
            )
        if self.walls["left"]:
            pygame.draw.line(
                sc, pygame.Color("darkorange"), (x, y + TILE), (x, y), self.thickness
            )

    ## Obtenez les rectangles représentant chaque mur de la cellule
    def get_rects(self):
        rects = []
        x, y = self.x * TILE, self.y * TILE
        if self.walls["top"]:
            rects.append(pygame.Rect((x, y), (TILE, self.thickness)))
        if self.walls["right"]:
            rects.append(pygame.Rect((x + TILE, y), (self.thickness, TILE)))
        if self.walls["bottom"]:
            rects.append(pygame.Rect((x, y + TILE), (TILE, self.thickness)))
        if self.walls["left"]:
            rects.append(pygame.Rect((x, y), (self.thickness, TILE)))
        return rects

    ## Vérifiez si une cellule voisine existe
    def check_cell(self, x, y):
        find_index = lambda x, y: x + y * cols
        if x < 0 or x > cols - 1 or y < 0 or y > rows - 1:
            return False
        return self.grid_cells[find_index(x, y)]

    ## Obtenez les cellules voisines qui n'ont pas été visitées
    def check_neighbors(self, grid_cells):
        self.grid_cells = grid_cells
        neighbors = []
        top = self.check_cell(self.x, self.y - 1)
        right = self.check_cell(self.x + 1, self.y)
        bottom = self.check_cell(self.x, self.y + 1)
        left = self.check_cell(self.x - 1, self.y)
        if top and not top.visited:
            neighbors.append(top)
        if right and not right.visited:
            neighbors.append(right)
        if bottom and not bottom.visited:
            neighbors.append(bottom)
        if left and not left.visited:
            neighbors.append(left)
        return choice(neighbors) if neighbors else False

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous définissons la classe Cell avec ses propriétés et méthodes pour dessiner les murs et vérifier les voisins.
✨ Vérifier la solution et pratiquer

Suppression des murs et génération du labyrinthe

Dans cette étape, nous allons créer des fonctions pour supprimer les murs et générer le labyrinthe.

## Fonction pour supprimer les murs entre deux cellules adjacentes
def remove_walls(current, next):
    dx = current.x - next.x
    if dx == 1:
        current.walls["left"] = False
        next.walls["right"] = False
    elif dx == -1:
        current.walls["right"] = False
        next.walls["left"] = False
    dy = current.y - next.y
    if dy == 1:
        current.walls["top"] = False
        next.walls["bottom"] = False
    elif dy == -1:
        current.walls["bottom"] = False
        next.walls["top"] = False


## Fonction pour générer le labyrinthe
def generate_maze():
    grid_cells = [Cell(col, row) for row in range(rows) for col in range(cols)]
    current_cell = grid_cells[0]
    array = []
    break_count = 1

    while break_count!= len(grid_cells):
        current_cell.visited = True
        next_cell = current_cell.check_neighbors(grid_cells)
        if next_cell:
            next_cell.visited = True
            break_count += 1
            array.append(current_cell)
            remove_walls(current_cell, next_cell)
            current_cell = next_cell
        elif array:
            current_cell = array.pop()
    return grid_cells

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous définissons la fonction remove_walls pour supprimer les murs entre les cellules adjacentes.
  • Nous créons la fonction generate_maze pour générer le labyrinthe en utilisant un algorithme de recherche en profondeur.
✨ Vérifier la solution et pratiquer

Ajout de nourriture au jeu

Dans cette étape, nous allons créer une classe Food pour ajouter des objets de nourriture au jeu.

## Classe pour représenter la nourriture dans le jeu
class Food:
    def __init__(self):
        ## Chargez l'image de la nourriture
        self.img = pygame.image.load("img/food.png").convert_alpha()
        self.img = pygame.transform.scale(self.img, (TILE - 10, TILE - 10))
        self.rect = self.img.get_rect()
        self.set_pos()

    ## Définissez la position de la nourriture aléatoirement
    def set_pos(self):
        self.rect.topleft = randrange(cols) * TILE + 5, randrange(rows) * TILE + 5

    ## Dessinez la nourriture à l'écran
    def draw(self):
        game_surface.blit(self.img, self.rect)

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous définissons la classe Food avec des méthodes pour définir la position et dessiner les objets de nourriture.
✨ Vérifier la solution et pratiquer

Déplacement du joueur et détection de collisions

Dans cette étape, nous allons configurer les contrôles, le déplacement du joueur et la détection de collisions.

## Vérifiez si le joueur entre en collision avec les murs
def is_collide(x, y):
    tmp_rect = player_rect.move(x, y)
    if tmp_rect.collidelist(walls_collide_list) == -1:
        return False
    return True

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous définissons la fonction is_collide pour vérifier si le joueur entre en collision avec les murs.
✨ Vérifier la solution et pratiquer

Gameplay et notation

Dans cette étape, nous allons implémenter la logique du gameplay, y compris la consommation de nourriture et la notation.

## Vérifiez si le joueur a consommé de la nourriture
def eat_food():
    for food in food_list:
        if player_rect.collidepoint(food.rect.center):
            food.set_pos()
            return True
    return False


## Vérifiez si la partie est terminée (le temps s'écoule)
def is_game_over():
    global time, score, record, FPS
    if time < 0:
        pygame.time.wait(700)
        player_rect.center = TILE // 2, TILE // 2
        [food.set_pos() for food in food_list]
        set_record(record, score)
        record = get_record()
        time, score, FPS = 60, 0, 60

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous définissons la fonction eat_food pour vérifier si le joueur a consommé de la nourriture.
  • Nous créons la fonction is_game_over pour vérifier si la partie est terminée lorsque le temps s'écoule.
✨ Vérifier la solution et pratiquer

Gestion des records

Dans cette étape, nous allons implémenter la conservation des records pour le jeu.

## Fonction pour obtenir le record actuel à partir d'un fichier
def get_record():
    try:
        with open("record") as f:
            return f.readline()
    except FileNotFoundError:
        with open("record", "w") as f:
            f.write("0")
            return "0"

## Fonction pour définir et mettre à jour le record dans un fichier
def set_record(record, score):
    rec = max(int(record), score)
    with open("record", "w") as f:
        f.write(str(rec))

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous définissons des fonctions pour récupérer le record actuel à partir d'un fichier et le mettre à jour.
✨ Vérifier la solution et pratiquer

Initialisation du jeu

Dans cette étape, nous allons effectuer les tâches d'initialisation du jeu.

## Initialisez Pygame et configurez la fenêtre du jeu
FPS = 60
pygame.init()
game_surface = pygame.Surface(RES)
surface = pygame.display.set_mode((WIDTH + 300, HEIGHT))
clock = pygame.time.Clock()

## Chargez les images d'arrière-plan
bg_game = pygame.image.load("img/bg_1.jpg").convert()
bg = pygame.image.load("img/bg_main.jpg").convert()

## Générez le labyrinthe
maze = generate_maze()

## Paramètres du joueur
vitesse_joueur = 5
img_joueur = pygame.image.load("img/0.png").convert_alpha()
img_joueur = pygame.transform.scale(
    img_joueur, (TILE - 2 * maze[0].épaisseur, TILE - 2 * maze[0].épaisseur)
)
rect_joueur = img_joueur.get_rect()
rect_joueur.center = TILE // 2, TILE // 2
directions = {
    "a": (-vitesse_joueur, 0),
    "d": (vitesse_joueur, 0),
    "w": (0, -vitesse_joueur),
    "s": (0, vitesse_joueur),
}
keys = {"a": pygame.K_LEFT, "d": pygame.K_RIGHT, "w": pygame.K_UP, "s": pygame.K_DOWN}
direction = (0, 0)

## Paramètres de la nourriture
liste_nourriture = [Food() for i in range(3)]

## Créez une liste de rectangles représentant les murs pour la détection de collisions
liste_collisions_murs = sum([cell.get_rects() for cell in maze], [])

## Timer, score et record
pygame.time.set_timer(pygame.USEREVENT, 1000)
temps = 60
score = 0
record = get_record()

## Polices d'écriture
font = pygame.font.SysFont("Impact", 150)
text_font = pygame.font.SysFont("Impact", 80)

## Le reste de votre code ira ici...

Dans cette étape :

  • Nous effectuons diverses tâches d'initialisation, y compris la configuration de Pygame, le chargement d'images, la génération du labyrinthe et l'initialisation des variables liées au joueur et à la nourriture.
✨ Vérifier la solution et pratiquer

Boucle principale du jeu

Dans cette étape, nous allons configurer la boucle principale du jeu et afficher les éléments du jeu.

## Boucle principale du jeu
while True:
    ## Affichez les images d'arrière-plan
    surface.blit(bg, (WIDTH, 0))
    surface.blit(game_surface, (0, 0))
    game_surface.blit(bg_game, (0, 0))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()
        if event.type == pygame.USEREVENT:
            temps -= 1

    ## Gérer les contrôles et le déplacement du joueur
    touches_appuyées = pygame.key.get_pressed()
    for key, key_value in keys.items():
        if touches_appuyées[key_value] and not is_collide(*directions[key]):
            direction = directions[key]
            break
    if not is_collide(*direction):
        rect_joueur.move_ip(direction)

    ## Dessinez le labyrinthe
    [cell.draw(game_surface) for cell in maze]

    ## Gameplay : Vérifiez si le joueur a consommé de la nourriture et si la partie est terminée
    if eat_food():
        FPS += 10
        score += 1
    is_game_over()

    ## Dessinez le joueur
    game_surface.blit(img_joueur, rect_joueur)

    ## Dessinez les éléments de nourriture
    [food.draw() for food in food_list]

    ## Le reste de votre code ira ici...

Dans cette étape :

  • Nous configurons la boucle principale du jeu qui gère les événements, le déplacement du joueur et le rendu du jeu.
✨ Vérifier la solution et pratiquer

Affichage des statistiques du jeu

Dans cette étape, nous allons afficher les statistiques du jeu sur l'écran.

    ## Dessinez les statistiques du jeu
    surface.blit(
        text_font.render("TIME", True, pygame.Color("cyan"), True), (WIDTH + 70, 30)
    )
    surface.blit(font.render(f"{temps}", True, pygame.Color("cyan")), (WIDTH + 70, 130))
    surface.blit(
        text_font.render("score:", True, pygame.Color("forestgreen"), True),
        (WIDTH + 50, 350),
    )
    surface.blit(
        font.render(f"{score}", True, pygame.Color("forestgreen")), (WIDTH + 70, 430)
    )
    surface.blit(
        text_font.render("record:", True, pygame.Color("magenta"), True),
        (WIDTH + 30, 620),
    )
    surface.blit(
        font.render(f"{record}", True, pygame.Color("magenta")), (WIDTH + 70, 700)
    )

    pygame.display.flip()
    clock.tick(FPS)

Dans cette étape :

  • Nous utilisons des polices pour afficher des informations liées au jeu telles que le temps, le score et le record.
  • Nous utilisons la méthode blit() pour dessiner le texte sur l'écran.
  • Nous utilisons la méthode flip() pour mettre à jour l'affichage.
✨ Vérifier la solution et pratiquer

Exécutez le jeu

Maintenant que nous avons terminé toutes les étapes, nous pouvons exécuter le jeu Labyrinthe en utilisant la commande suivante :

cd ~/projet
python maze.py
Capture d'écran d'exécution du jeu Labyrinthe
✨ Vérifier la solution et pratiquer

Sommaire

Dans ce projet, nous avons divisé le processus de construction d'un jeu de labyrinthe utilisant Pygame en dix étapes claires et gérées facilement. Vous allez apprendre à configurer l'environnement du jeu, créer des cellules de labyrinthe, générer le labyrinthe, gérer le mouvement du joueur et la détection de collisions, implémenter le gameplay et le scoring, gérer les records, et bien plus encore. En suivant ces étapes, vous serez capable de créer un jeu de labyrinthe entièrement fonctionnel en Python.