Labyrinthe 3D

en Python

laby-3d
Philippe Escalle CTO

Vous rêvez de construire votre propre labyrinthe 3D et de vous perdre virtuellement sans risquer d’appeler les secours ? Bonne nouvelle ! Avec Python, c'est possible. Pour cela il existe 4 bibliothèques à installer avec pip.

  • Pygame
    Pygame est une bibliothèque qui gère tout ce qui est fun : graphismes, sons, et interactions.

  • Numpy
    Si vous avez toujours trouvé que les maths étaient votre ennemi juré, Numpy va changer votre vie. Cette bibliothèque permet de gérer des calculs complexes sans douleur (ou presque).

  • Math
    La bibliothèque standard math vous aide à résoudre tous les problèmes trigonométriques liés à votre jeu. Cosinus, sinus et angles ne seront plus un mystère pour vous.

  • Time
    Vous voulez chronométrer le temps que vous mettez pour vous échapper du labyrinthe ? Le module time est là pour ajouter une touche de suspense.

    Bon, le jeu tourne en 118 lignes ! c'est presque rien non ? Le rendu est basique mais juste ce qu'il faut pour se faire une idée de comment fonctionne python pour faire un petit jeu. Pour se déplacer, il suffit d'utiliser les flèches du clavier.



    Voici le code

  • 
    import pygame
    import math
    import time
    
    # Configuration de l'écran et du jeu
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 600
    FOV = math.pi / 3  # Champ de vision (Field of View)
    NUM_RAYS = 120
    MAX_DEPTH = 20
    TEXTURE_SIZE = 64
    MAP_SIZE = 10
    
    # Définition du labyrinthe (1 = mur, 0 = espace libre, 2 = sortie)
    maze = [
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
        [1, 0, 1, 0, 0, 0, 0, 1, 0, 1],
        [1, 0, 1, 0, 1, 1, 0, 1, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 1, 0, 1],
        [1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 1, 1, 1, 1, 1, 0, 2, 1],  # Sortie au point (8,8)
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    ]
    
    # Position et angle du joueur (entrée du labyrinthe)
    player_pos = [1.5, 1.5]
    player_angle = 0
    player_speed = 0.1
    rotation_speed = 0.05
    
    # Initialisation de Pygame
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 36)
    
    # Compte à rebours avant le départ
    for count in range(3, 0, -1):
        screen.fill((0, 0, 0))
        text = font.render(f'{count}...', True, (255, 255, 255))
        screen.blit(text, (SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2))
        pygame.display.flip()
        time.sleep(1)
    
    screen.fill((0, 0, 0))
    text = font.render('Find the exit!', True, (255, 255, 255))
    screen.blit(text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2))
    pygame.display.flip()
    time.sleep(1)
    
    start_time = time.time()
    
    # Fonction de rendu des rayons pour simuler la 3D
    def cast_rays():
        for i in range(NUM_RAYS):
            angle = player_angle - (FOV / 2) + (i / NUM_RAYS) * FOV
            sin_a = math.sin(angle)
            cos_a = math.cos(angle)
            dist = 0
            while dist < MAX_DEPTH:
                x = int(player_pos[0] + dist * cos_a)
                y = int(player_pos[1] + dist * sin_a)
                if maze[y][x] == 1:
                    break
                dist += 0.05
            depth_correction = dist * math.cos(player_angle - angle)
            wall_height = int(TEXTURE_SIZE / (depth_correction + 0.0001) * 5)
            color = 255 / (1 + dist * dist * 0.1)
            if maze[y][x] == 2:
                pygame.draw.rect(screen, (0, 255, 0), (i * (SCREEN_WIDTH / NUM_RAYS), SCREEN_HEIGHT//2 - wall_height // 2, SCREEN_WIDTH / NUM_RAYS, wall_height))
            else:
                pygame.draw.rect(screen, (color, color, color), (i * (SCREEN_WIDTH / NUM_RAYS), SCREEN_HEIGHT//2 - wall_height // 2, SCREEN_WIDTH / NUM_RAYS, wall_height))
    
    # Boucle principale du jeu
    running = True
    while running:
        screen.fill((0, 0, 0))
        cast_rays()
        
        # Vérification de la sortie
        if int(player_pos[0]) == 8 and int(player_pos[1]) == 8:
            end_time = time.time()
            elapsed_time = end_time - start_time
            screen.fill((0, 0, 0))
            text = font.render(f'You escaped in {elapsed_time:.2f} seconds!', True, (0, 255, 0))
            screen.blit(text, (SCREEN_WIDTH // 2 - 200, SCREEN_HEIGHT // 2))
            pygame.display.flip()
            pygame.time.delay(5000)
            running = False
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
    
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            player_angle -= rotation_speed
        if keys[pygame.K_RIGHT]:
            player_angle += rotation_speed
        if keys[pygame.K_UP]:
            new_x = player_pos[0] + player_speed * math.cos(player_angle)
            new_y = player_pos[1] + player_speed * math.sin(player_angle)
            if maze[int(new_y)][int(new_x)] == 0 or maze[int(new_y)][int(new_x)] == 2:
                player_pos[0] = new_x
                player_pos[1] = new_y
        if keys[pygame.K_DOWN]:
            new_x = player_pos[0] - player_speed * math.cos(player_angle)
            new_y = player_pos[1] - player_speed * math.sin(player_angle)
            if maze[int(new_y)][int(new_x)] == 0:
                player_pos[0] = new_x
                player_pos[1] = new_y
    
        pygame.display.flip()
        clock.tick(60)
    
    pygame.quit()