Coder le jeu Geometry dash en python

Résolu
Utilisateur anonyme -  
 Utilisateur anonyme -

Bonjour bonjour !!

Je fais un geometry dash pour l'école et je suis de ce qu'il y a de plus débutant.

J'ai pour l'instant mon personnage qui se déplace et qui saute. L'étape suivant est de créer des plateformes dans l'air et des obstacles ; ainsi que de faire défiler le background. Je commence par les obstacles, et les plateformes mais j'arrive pas a les connecter a mon code.

Ma question est la suivante ; est-ce que quelqu'un aurait un lien vers un tutoriel de plateforme et d'obstacles que je pourrai facilement adapter et comprendre pour mon code ?

Merci

6 réponses

  1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    Sans voir ton code, difficile de réponder.

    Mais en faisant une petite recherche google, j'ai trouvé cette vidéo qui me paraît répondre exactement à ta question, et la description fournit le lien vers le code.

    Le code est basé sur ursina.

    Bonne chance

    2
  2. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    Si tu ne veux pas utiliser ursina et que tu préfère utiliser pygame, tu peux regarder ce dépôt.

    Bonne chance

    1
  3. jouat
     

    Salut.

    Le truc, c'est que pour faire même un simple jeu, il faut beaucoup se familiariser avec la bibliothèque dont on veut se servir, donc en faisant des tas de tests, et bien évidemment cela prend du temps, faire un jeu avec obstacles et plateformes demande beaucoup de temps, que ce soit sur la mécanique du jeu ou sur la réflexion, stratégie du jeu, conception des maps, etc. Sans compter qu'évidemment il faut maitriser les concepts primaires de python, y compris l'objet, faire un jeu complexe sans modèle objet est pour moi mission impossible, enfin, c'est faisable mais au détriment de la lisibilité et organisation du code, surtout qu'en python tout est objet.
    Faire un jeu avec pygame, c'est utiliser des sprites, un sprite pygame doit avoir comme attributs image et rect, donc player, obstacles, plateformes et toutes entités doivent être des sprites.


    Je ne sais ce que tu nommes par "geometry dash", faire apparaitre des obstacles que le joueur doit éviter ou collecter, ce n'est pas difficile (enfin pour si peu que l'on connaisse un peu pygame).

    .

    Fais à la va vite selon ton code.

    import pygame
    import random
    
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 600
    SCREEN_COLOR = 120, 170, 255
    
    FLOOR_Y = 550
    
    PLAYER_COLOR = 255, 255, 255
    
    EVENT_OBSTACLE_SPAWN = pygame.USEREVENT + 1
    
    FPS = 60
    
    
    class Floor(pygame.sprite.Sprite):
        def __init__(self, y):
            super().__init__()
            self.image = pygame.Surface((SCREEN_RECT.w, 100))
            self.image.fill((100, 200, 80))
            self.rect = self.image.get_rect()
            self.rect.topleft = 0, y
    
    
    class Player(pygame.sprite.Sprite):
        def __init__(self, x, y):
            super().__init__()
            self.image = pygame.Surface((50, 50))
            self.image.fill(PLAYER_COLOR)
            self.rect = self.image.get_rect()
            self.rect.bottomleft = x, y
            self.x = x
            self.y = y
            self.jumping = False
            self.jump_count = 20
    
        def move(self, amount):
            self.rect.x += amount
    
        def jump(self):
            self.jumping = True
    
        def collide(self, sprites):
            # Retourne les sprites en collision avec le joueur
            return tuple(sprites[i] for i in self.rect.collidelistall(sprites))
    
        def update(self):
            if self.jumping:
                # step = -(0.5 * self.jump_count ** 2)
                step = -(0.05 * self.jump_count ** 2) * (60 / FPS)
                if self.jump_count > 0:
                    step *= -1
                self.rect.y -= step
                self.jump_count -= 1
                if self.rect.bottom >= self.y:
                    self.rect.bottom = self.y
                    self.jumping = False
                    self.jump_count = 20
    
    
    class Obstacle(pygame.sprite.Sprite):
        def __init__(self, x, y, width, height):
            super().__init__()
            self.image = pygame.Surface((width, height), pygame.SRCALPHA)
            self.rect = self.image.get_rect()
            self.rect.bottomleft = x, y
    
        def update(self):
            self.rect.x -= 5
    
    
    class Friend(Obstacle):
        points = 10
        def __init__(self, x, y):
            super().__init__(x, y, 60, 60)
            pygame.draw.circle(self.image, (0, 155, 155), (30, 30), 30)
    
    
    class Ennemy(Obstacle):
        points = -15
        def __init__(self, x, y):
            super().__init__(x, y, 60, 60)
            pygame.draw.polygon(self.image, (0, 0, 0), ((30, 0), (0, 60), (60, 60)))
    
    
    def obstacle_spawn():
        # Choix d'un obstacle (30% ami, 70% ennemi)
        obstacle_class = random.choices((Friend, Ennemy), (3, 7))[0]
        obstacle = obstacle_class(SCREEN_RECT.w, FLOOR_Y)
        draw_group.add(obstacle)
        obstacles_group.add(obstacle)
    
    
    def spawn_timer():
        ms = random.randrange(500, 1100)
        pygame.time.set_timer(EVENT_OBSTACLE_SPAWN, ms)
    
    
    def sprites_clear(surface, rect):
        surface.fill(SCREEN_COLOR, rect)
    
    
    def pause():
        clock = pygame.time.Clock()
        while True:
            clock.tick(FPS)
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN and event.key == pygame.K_p:
                    return
    
    
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    SCREEN_RECT = screen.get_rect()
    pygame.mouse.set_visible(False)
    pygame.display.set_caption("test jeu")
    
    draw_group = pygame.sprite.RenderUpdates()
    obstacles_group = pygame.sprite.Group()
    
    player = Player(150, FLOOR_Y)
    draw_group.add(player)
    
    floor = Floor(FLOOR_Y)
    draw_group.add(floor)
    
    screen.fill(SCREEN_COLOR)
    pygame.display.update()
    
    clock = pygame.time.Clock()
    running = True
    points = 0
    spawn_timer()
    game_paused = False
    
    while running:
        clock.tick(FPS)
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP and not player.jumping:
                    player.jump()
                elif event.key == pygame.K_p:
                    game_paused = not game_paused
                    if game_paused:
                        pause()
                        game_paused = False
                elif event.key == pygame.K_ESCAPE:
                    running = False
            elif event.type == EVENT_OBSTACLE_SPAWN:
                obstacle_spawn()
                spawn_timer()
                draw_group.remove(player)
                draw_group.add(player)
            elif event.type == pygame.QUIT:
                running = False
    
        # Collision obstacles avec le joueur
        for sprite in player.collide(obstacles_group.sprites()):
            points += sprite.points
            obstacles_group.remove(sprite)
            draw_group.remove(sprite)
            print("points : ", points)
    
        # Suppression des sprites hors écran
        for sprite in obstacles_group.copy().sprites():
            if sprite.rect.right < SCREEN_RECT.x:
                obstacles_group.remove(sprite)
                draw_group.remove(sprite)
    
        draw_group.clear(screen, sprites_clear)
        draw_group.update()
        rects = draw_group.draw(screen)
        pygame.display.update(rects)
    
    
    pygame.quit()
    


    Maintenant si tu veux créer également des plateformes avec des ennemis et des objets à collecter, cela ne va pas pouvoir se faire à la volée, il va falloir créer une map (ou plusieurs si niveaux), gérer la vie, le score, et tout ce qui est nécessaire au bon fonctionnement du jeu.

    .

    Alors pour un simple projet d'étudiant, peut-être devrais-tu revoir tes prétentions à la baisse et conceptualiser un simple jeu 2d plus simple, pas forcément un pong (qui même pour un novice n'est pas si simple que ça), mais quelque chose à près similaire niveau complexité.

    .
    Bon courage.

    1
    1. Utilisateur anonyme
       

      Merci Jouat !!!

      Oui je vais très certainement redescendre un petit peu au niveau du jeu xd

      Merci beaucoup !!!

      0
  4. Utilisateur anonyme
     

    Bonsoir, c'est encore moi (et la dernière fois je pense)

    J'ai un dernier problème : j'essaie désespérément de faire afficher le score en haut de l'écran  en fonction du temps, et y a un problème que je ne comprends pas ligne 139

    import pygame
    import random
    
    
    pygame.init()
    
    
    
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 600
    SCREEN_COLOR = 120, 170, 255
    
    SOL_Y = 550
    
    PLAYER_COLOR = 255, 255, 255
    PLAYER_HEIGHT = 30
    PLAYER_WIDTH = 30
    EVENT_OBSTACLE_SPAWN = pygame.USEREVENT + 1
    
    
    FPS = 60
    
    
    
    class Sol(pygame.sprite.Sprite):
        def __init__(self, y):
            super().__init__()
            self.image = pygame.Surface((SCREEN_RECT.w, 100))
            self.image.fill((100, 200, 80))
            self.rect = self.image.get_rect()
            self.rect.topleft = 0, y
    
    
    class Player(pygame.sprite.Sprite):
        def __init__(self, x, y):
            super().__init__()
            self.image = pygame.Surface((30, 30))
            self.image.fill(PLAYER_COLOR)
            self.rect = self.image.get_rect()
            self.rect.bottomleft = x, y
            self.x = x
            self.y = y
            self.jumping = False
            self.jump_count = 20
    
        def move(self, amount):
            self.rect.x += amount
    
        def jump(self):
            self.jumping = True
    
        def collision(self, sprites):
            for sprite in sprites:
                if isinstance(sprite, Cercle):
                    if self.rect.colliderect(sprite.rect):
                        if self.rect.bottom <= sprite.rect.centery:
    
                            self.rect.bottom = sprite.rect.top
                        elif self.rect.top >= sprite.rect.centery:
                            pygame.time.wait(2000)
                            quit()
    
    
                        else:
    
                            if self.rect.centerx < sprite.rect.centerx:
                                self.rect.right = sprite.rect.left
    
                            else:
                                self.rect.left = sprite.rect.right
    
                elif isinstance(sprite, Triangle):
                    if self.rect.colliderect(sprite.rect):
                        if self.rect.bottom <= sprite.rect.centery:
                            self.rect.bottom = sprite.rect.top
    
                        elif self.rect.top >= sprite.rect.centery:
                            pygame.time.wait(2000)
                            quit()
    
                        else:
    
                            if self.rect.centerx < sprite.rect.centerx:
                                self.rect.right = sprite.rect.left
    
                            else:
                                self.rect.left = sprite.rect.right
    
                elif isinstance(sprite, Rectangle):
                    if self.rect.colliderect(sprite.rect):
                        if self.rect.bottom <= sprite.rect.centery:
                            self.rect.bottom = sprite.rect.top
    
                        elif self.rect.top >= sprite.rect.centery:
                            pygame.time.wait(2000)
                            quit()
    
                        else:
                            if self.rect.centerx < sprite.rect.centerx:
                                self.rect.right = sprite.rect.left
    
                            else:
    
                                self.rect.left = sprite.rect.right
    
            # Retourne les sprites en collision avec le joueur
    
            return tuple(s for s in sprites if s.rect.colliderect(self.rect))
    
    
        def update(self):
            if self.jumping:
                step = -(0.05 * self.jump_count ** 2) * (60 / FPS)
                if self.jump_count > 0:
                    step *= -1
                self.rect.y -= step
                self.jump_count -= 1
                if self.rect.bottom >= self.y:
                    self.rect.bottom = self.y
                    self.jumping = False
                    self.jump_count = 20
    
    
    class ScoreBoard:
        def __init__(self, screen_rect):
            self.screen_rect = screen_rect
            self.score = 0
            self.font = pygame.font.SysFont('Arial', 30)
            self.color = (255, 255, 255)
    
        def update1(self, time):
            self.score = int(time / 1000)
    
        def draw(self, screen):
            text_surface = self.font.render(f"Score: {self.score}", True, self.color)
            text_rect = text_surface.get_rect(topleft=(0, 0))
            screen.blit(text_surface, text_rect)
    
    score_board = ScoreBoard(SCREEN_WIDTH, SCREEN_HEIGHT)
    SCREEN_HEIGHT = 600
    
    class Obstacle(pygame.sprite.Sprite):
        def __init__(self, x, y, width, height):
            super().__init__()
            self.image = pygame.Surface((width, height), pygame.SRCALPHA)
            self.rect = self.image.get_rect()
            self.rect.bottomleft = x, y
    
        def update(self):
            self.rect.x -= 6
    
    
    class Cercle(Obstacle):
        points = 10
    
        def __init__(self, x, y):
            super().__init__(x, y, 60, 60)
            pygame.draw.circle(self.image, (0, 155, 155), (30, 30), 30)
    
    
    class Triangle(Obstacle):
        points = -15
    
        def __init__(self, x, y):
            super().__init__(x, y, 60, 60)
            pygame.draw.polygon(self.image, (0, 255, 0), ((30, 0), (0, 60), (60, 60)))  # formation du triangle
    
    
    class Rectangle(Obstacle):
        points = 10
    
        def __init__(self, x, y):
            super().__init__(x, y, 70, 135)
            pygame.draw.rect(self.image, (12, 48, 255), (5, 5, 130, 130))
    
    
    class LongRectangle(Obstacle):
        points = 10
    
        def __init__(self, x, y):
            super().__init__(x, y, 620, 65)
            pygame.draw.rect(self.image, (255, 255, 0), (15, 15, 230, 230))
    
    
    # le spawn ; c'est une sorte de création en direct d'objets ou de personnages (ici ça va être les obstacles)
    def obstacle_spawn():
        # Choix de l'obstacle (en mode tu choisis si tu veux plus de triangle ou de cercles
        obstacle_class = random.choices((Cercle, Triangle, Rectangle, LongRectangle), (10, 14, 6, 3))[0]
        obstacle = obstacle_class(SCREEN_RECT.w, SOL_Y)
        draw_group.add(obstacle)
        obstacles_group.add(obstacle)
    
    
    def spawn_timer():
        ms = random.randrange(500, 1100)
        pygame.time.set_timer(EVENT_OBSTACLE_SPAWN, ms)
    
    
    def sprites_clear(surface, rect):
        surface.fill(SCREEN_COLOR, rect)
    
    
    # applicatio,
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    SCREEN_RECT = screen.get_rect()
    pygame.mouse.set_visible(False)
    pygame.display.set_caption("Geo update")
    
    draw_group = pygame.sprite.RenderUpdates()
    obstacles_group = pygame.sprite.Group()
    
    player = Player(100, SOL_Y)
    draw_group.add(player)
    
    sol = Sol(SOL_Y)
    draw_group.add(sol)
    
    screen.fill(SCREEN_COLOR)
    pygame.display.update()
    
    clock = pygame.time.Clock()
    running = True
    points = 0
    spawn_timer()
    
    # boucle principale
    running = True
    while running:
        clock.tick(FPS)
        score_board.update1(pygame.time.get_ticks())
    
        sprites_clear(screen, SCREEN_WIDTH, SCREEN_HEIGHT)
        score_board.draw(screen)
        draw_group.update()
        draw_group.draw(screen)
        obstacles_group.update()
        pygame.display.update(SCREEN_HEIGHT, SCREEN_WIDTH)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == EVENT_OBSTACLE_SPAWN:
                obstacle_spawn()
                spawn_timer()
    
    
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP or pygame.K_SPACE and not player.jumping:
                    player.jump()
    
            elif event.type == EVENT_OBSTACLE_SPAWN:
                obstacle_spawn()
                spawn_timer()
                draw_group.remove(player)
                draw_group.add(player)
    
        if pygame.sprite.spritecollide(player, obstacles_group, False):
            running = False
    
        # Collision obstacles avec le joueur
        for sprite in player.collision(obstacles_group.sprites()):
            # systeme de points à changer
            points += sprite.points
            obstacles_group.remove(sprite)
            draw_group.remove(sprite)
            print("points : ", points)
    
        # Suppression des sprites hors écran
        for sprite in obstacles_group.copy().sprites():
            if sprite.rect.right < SCREEN_RECT.x:
                obstacles_group.remove(sprite)
                draw_group.remove(sprite)
    
        draw_group.clear(screen, sprites_clear)
        pygame.display.update()
    
    pygame.quit()
    

    donc j'ai créer une classe pour le score, et je l'ai aussi appelé dans la boucle principale mais je ne comprends pas le problème

    Pourquoi ??

    Merci :))

    1
    1. jouat
       

      Salut,

      Ta classe ScoreBoard prend un seul argument screen_rect (pourquoi ?), or tu lui passes 2 paramètres lorsque tu l'instancies, SCREEN_WIDTH et SCREEN_HEIGHT, donc forcément python bronche.

      Cette classe n'a nul besoin de cela, elle doit juste recevoir la position x, y où le score doit être affiché, rien de plus, et encore, on pourrait même s'en passer et gérer la position hors cette classe.

      .
      Qu'est censée faire ce que tu as fait dans la collision du joueur ? Je ne comprends pas pourquoi tu fais quitter le jeu, ni pourquoi tu veux gérer la collision différemment en fonction du type d'obstacle.

      .

      Pour n'importe quel type d'élément à afficher, utilise un sprite.

      .

      class ScoreBoard(pygame.sprite.Sprite):
          def __init__(self, x, y):
              super().__init__()
              self.x = x
              self.y = y
              self.score = 0
              self.font = pygame.font.SysFont('Arial', 30)
              self.color = (255, 255, 255)
              self.image = self.font.render('0', True, self.color)
              self.rect = self.image.get_rect()
              self.rect.topright = x, y
      
          def add(self, amount):
              self.score += amount
              self.image = self.font.render(str(self.score), True, self.color)
              self.rect = self.image.get_rect()
              self.rect.topright = self.x, self.y

      .

      On l'ajoute ensuite, comme pour les autres objets, au groupe d'affichage.

      .

      # ....
      
      sol = Sol(SOL_Y)
      draw_group.add(sol)
      
      score = ScoreBoard(SCREEN_RECT.right - 10, 10)
      draw_group.add(score)
      
      # ...

      .
      Et update du score dans la boucle du jeu lorsque le joueur entre en collision avec les obstacles.

      .

      # Collision obstacles avec le joueur
      for sprite in player.collision(obstacles_group.sprites()):
          obstacles_group.remove(sprite)
          draw_group.remove(sprite)
          score.add(sprite.points)

      .
      Cela fonctionne en laissant le code de la méthode collision que je t'avais montré.

      2
      1. Utilisateur anonyme > jouat
         

        Jvais essayer ça tout à l'heure. 

        Mon but avec les collisions :

        Pour les triangles et les cercles des qu'il le touche j'ai mis un temps d'arrêt pour faire afficher un message et j'enlèverai le quit plus tard lorsque j'aurais mis de presser une touche pour arriver à la page d'accueil ou pour recommencer le jeu 

        Et pour les rectangles en hauteur c'est pour qu'il puisse passer dessus (mais je vois que c'est pas le bon moyen :(

        Merci :)

        1
      2. jouat > Utilisateur anonyme
         

        Bonsoir.

        .

        Si tu souhaites que le joueur puisse se balader sur les obstacles, alors il va falloir revoir la façon dont le joueur saute, c-à-d gérer cela en 2 phases, une d'ascension, celle-là est simple, et donc une  phase de chute tant que le joueur n'a pas touché une surface sur laquelle il peut se mouvoir.

        .

        Il faudra donc détecter lorsque le joueur chute qu'il entre en collision avec un élément solide, les collisions est une des choses les plus difficiles à gérer dans un jeu, cela peut rapidement se complexifier et devenir un cauchemar ^^

        .

        Tu devrais réduire ton code au plus simple pour créer ton système de jump,  un sol, un simple bloc (voir plusieurs à différentes hauteurs), et évidemment le joueur. Il y a pas mal d'exemples sur internet concernant la mécanique des sauts.

        2
      3. Utilisateur anonyme > jouat
         

        Oui je vais suivre ton conseil, ça paraît plus clair que ce que je commençais à faire. 

        Merci beaucoup !!

        1
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Utilisateur anonyme
     

    Salut merci de me répondre :)

    Ouais j'ai vu cette vidéo 
    Mon code ressemble à ça; mais je sais pas j'arrive pas :(

    import pygame
    
    #taille de l'ecran et initialisation
    LARGEUR_ECRAN = 1600
    HAUTEUR_ECRAN = 850
    
    
    pygame.display.set_caption("test jeu")
    ecran = pygame.display.set_mode([LARGEUR_ECRAN, HAUTEUR_ECRAN])
    
    pygame.init()
    
    #saut
    x = 800 #position du cube au début
    y = 600 #position du cube au début
    width = 80
    height = 80
    vel = 15
    
    isJump = False
    jumpCount = 10 #hauteur du saut
    
    """on peut mettre des classes entre là et la boucle continuelle"""
    
    #boucle
    run = True
    
    while run:
        pygame.time.delay(30) #clock
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        keys = pygame.key.get_pressed()
    
        #directions
        if keys[pygame.K_LEFT] and x > vel:
            x -= vel
        if keys[pygame.K_RIGHT] and x < 1600 - vel - width:
            x += vel
    
        #saut
        if not (isJump):
    
            if keys[pygame.K_SPACE]:
                isJump = True
        else:
            if jumpCount >= -10:
                y -= (jumpCount * abs(jumpCount)) * 0.5
                jumpCount -= 1
            else:
                jumpCount = 10
                isJump = False
    
    
        #appeler les elements
        ecran.fill((120, 170, 255))
        pygame.draw.rect(ecran, (100, 200, 80), (0, 680, 1600, 350))
        pygame.draw.rect(ecran, (255, 255, 255), (x, y, width, height))
        pygame.display.update()
    
    pygame.quit()
    0
  7. Utilisateur anonyme
     

    Je vais regarder, merci :))

    0