Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Pygame]Problème de mouvements de personnages

Un personnage part en retard par rapport à l'autre!

    23 mars 2015 à 12:11:06

    Bonjour, je suis en train de travailler sur un projet python, et j'ai un soucis qui me bloque pas mal.

    Je débute en Python, et avec 3 camarades nous réalisions le projet pour la spé ISN de term.

    Dans les grandes lignes : le projet est un jeu, qui consiste à se faire battre en duel deux joueurs. Les deux joueurs sont censés se rapprocher avec un mouvement accéléré et rectiligne, les joueurs ne contrôlant que la position de l'arme des personnages (ce qui n'est pas encore implémenté). Le mouvement se fait donc automatiquement.

    Seulement voilà, problème : Mon personnage de gauche part en retard par rapport au personnage de droite, et je n'arrive pas à savoir pourquoi!

    Je vous poste mon programme, et l'image qui symbolise les personnages pour le moment (On ne rigole pas sur le choix de l'image, je l'ai prise d'un tutoriel du site :D )

    #Importation de pygame
    import pygame
    from pygame.locals import *
    pygame.init()
    
    #Ouverture de la fenêtre
    fenetre = pygame.display.set_mode((900, 480))
    
    #chargement des images
    perso1 = pygame.image.load("perso.png").convert_alpha() #Personnage à gauche (perso1)
    perso2 = perso1                                         #Personnage à droite (perso2)
    
    fond = pygame.Surface(fenetre.get_size()) #création de la surface pour le fond
    fond.fill((255,255,255)) #remplissage du fond en blanc
    fond = fond.convert()
    fenetre.blit(fond,(0,0))
                  
    #Position des personnages
    dx = 1         #vitesse des personnages
    pos1 = perso1.get_rect()               
    pos2 = perso2.get_rect(centerx=850)
    pygame.display.update()
    
    clock = pygame.time.Clock()  #Horloge
    FPS = 100  #plus haut taux de rafraichissements par secondes désiré
    
    dpos1, dpos2 = Rect(0,0, 100, 100), Rect(0,0, 100, 100) #Anciennes pos à "nettoyer"
    dirty_rects = [dpos1, dpos2, pos1, pos2]
    
    
    
    #mouvement
    run = True 
    while run:
            millisecondes = clock.tick(FPS) #temps depuis la dernière frame
            secondes = millisecondes / 1000.0
            for event in pygame.event.get(): 
                    if event.type == QUIT: #L'utilisateur quitte
                            run = False
                            break
                    elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: #l'utilisateur appuye sur escape
                            run = False
                            break
            fenetre.blit(fond, (0,0))
            dpos1.center, dpos2.center = pos1.center, pos2.center
            pos1.centerx += dx * secondes #float
            pos2.centerx += -dx * secondes
            print("pos2=",pos2) #Juste pour le déboggage
            print("pos1=",pos1)
            dx = 1.1*dx #accélération
            fenetre.blit(perso1, pos1)
            fenetre.blit(perso2, pos2)
            pygame.display.update(dirty_rects) #permet de n'actualiser qu'une partie de l'écran
            if pos1.colliderect(pos2): 
                      run = False
                      break
            clock.tick(FPS) #Régulation du framerate
    pygame.quit()
    
    
    
    
    

    Voilà l'image:

    J'ai utilisé quelques astuces pour certains problèmes que je n'arrivait pas à régler (sur la méthode des dirty_rects notamment ...) et je n'ai également pas utilisé de classes, s'il le faut vraiment j’essaierai d'en créer mais pour le moment je me débrouille sans.

    Je précise également que ce programme n'est pas le code final, ce n'est que la fonction déplacement, que j'implanterais dans la boucle principale dès que j'aurais réussi à la faire fonctionner ...

    Merci de prendre du temps et de m'aider, je suis un peu bloqué! ^^'

    -
    Edité par EydeeN 23 mars 2015 à 12:18:11

    • Partager sur Facebook
    • Partager sur Twitter
      23 mars 2015 à 13:38:34

      C'est juste que les pygame.Rect n'autorisent que des int comme position et taille. Donc quand tu fais pos1.centerx += dx * secondes ça s'arrondi...

      Aussi pour tes dpos1 et dpos2, tu dois faire une copie des rects précédants. Sinon dpos1 est pos1. Tu changes une fois le centre de l'un et l'autre change aussi. C'est pas ce que tu veux. :)

      Voici un exemple:

      !/usr/bin/env python

      -- coding: utf-8 --

      Importation de pygame

      import pygame from pygame.locals import * pygame.init()

      Ouverture de la fenêtre

      fenetre = pygame.display.set_mode((900, 480))

      chargement des images

      perso1 = pygame.image.load("perso.png").convert_alpha() #Personnage à gauche (perso1) perso2 = perso1 #Personnage à droite (perso2)

      fenetre.fill((255,255,255)) #remplissage du fond en blanc pygame.display.flip()

      Position des personnages

      dx = 1 #vitesse des personnages pos1 = perso1.get_rect() x1 = pos1.centerx pos2 = perso2.get_rect(centerx=850) x2 = pos2.centerx

      clock = pygame.time.Clock() #Horloge FPS = 100 #plus haut taux de rafraichissements par secondes désiré

      dpos1, dpos2 = pos1.copy(), pos2.copy() #Anciennes pos à "nettoyer" dirty_rects = [dpos1, dpos2, pos1, pos2]

      mouvement

      run = True while run:

      millisecondes = clock.tick(FPS) #temps depuis la dernière frame
      secondes = millisecondes / 1000.0
      for event in pygame.event.get():
          if event.type == QUIT: #L'utilisateur quitte
              run = False
              break
          elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: #l'utilisateur appuye sur escape
              run = False
              break
                      
      dx = 1.05 * dx #accélération
      dpos1.center, dpos2.center = pos1.center, pos2.center
      x1 += dx * secondes #float
      pos1.centerx = x1 # Ici il y a arrondi. Mais x1 conserve la position exacte
      x2 += -dx * secondes
      pos2.centerx = x2
      
      if pos1.colliderect(pos2):
          run = False
      
      fenetre.fill((255, 255, 255, 255))
      fenetre.blit(perso1, pos1)
      fenetre.blit(perso2, pos2)
      pygame.display.update(dirty_rects) #permet de n'actualiser qu'une partie de l'écran
      

      pygame.quit()

      </pre>

      -
      Edité par Dan737 23 mars 2015 à 13:40:33

      • Partager sur Facebook
      • Partager sur Twitter
        24 mars 2015 à 14:01:05

        Merci bcp d'avoir répondu, je regarderais en détail ce soir !

        EDIT: Waw ça fonctionne parfaitement maintenant :D

        J'ai bien compris pourquoi certaines choses bloquaient grâce à vous, je vais donc pouvoir modifier un peu mon programme pour l'optimiser, j'avais fait certains choix pour contourner des problèmes mais maintenant ils n'ont plus de sens x) Notamment pour les dirty rects, je faisais   dpos1, dpos2 = pos1, pos2   afin de stocker les anciennes positions dans ma liste dirty_rects, mais évidemment sur le coup mes dpos étaient actualisés en même temps que les pos ... J'avais donc eu l'idée de créer d'autres rectangles aux dimensions de l'image, suivant l'ancienne position de l'image afin de les actualiser eux ...

        J'ai bien un prof pour m'aider, mais presque toutes les fois où je lui ai demandé de l'aide il n'a pas su m'apporter de réponse, heureusement que j'arrivais à me dépatouiller tout seul --'

        Je vous remercie donc pour ces précisions, et je pense que je n'hésiterais pas à redemander de l'aide si je bloque encore :)

        Much love \o/

         RE-EDIT :  Finalement les pos.copy() ne me permettent pas d'utiliser le rafraîchissement par dirty_rects comme je l'entendait au départ mais c'est pas grave, la méthode en utilisant les centre des rects marche très bien alors je vais garder ça.

        -
        Edité par EydeeN 24 mars 2015 à 21:03:54

        • Partager sur Facebook
        • Partager sur Twitter
          24 mars 2015 à 22:25:10

          Content d'avoir pu t'aider! :)

          EydeeN a écrit:

           RE-EDIT :  Finalement les pos.copy() ne me permettent pas d'utiliser le rafraîchissement par dirty_rects comme je l'entendait au départ mais c'est pas grave, la méthode en utilisant les centre des rects marche très bien alors je vais garder ça.

          Pourtant c'est un bon truc les dirty rects, lorsque le fond est statique. Bon dans ton cas, un fill marche tout aussi bien (et est plus rapide). Mais si tu voulais mettre une image en background, ça vaut le coup de le faire.

          Pour l'exemple je crée un background blanc avec un bandeau marron. Je ne nettoie qu'aux endroits strictement nécessaires.

          #!/usr/bin/env python
          # -*- coding: utf-8 -*-
          
          import pygame
          from pygame.locals import *
          
          pygame.init()
          
          fenetre = pygame.display.set_mode((900, 480))
          # Création d'un fond blanc avec un bandeau bleu
          background = pygame.Surface((900, 480))
          background.fill((255,255,255))
          background.fill((65, 50, 10), pygame.Rect(70, 110, 760, 100))
           
          #chargement de l'image
          perso_img = pygame.image.load("perso.png").convert_alpha()
          
          fenetre.blit(background, (0, 0))
          pygame.display.flip()
          
          #Position des personnages
          dx = 50         #vitesse des personnages
          rect1 = perso_img.get_rect(midtop=(50, 50))
          x1 = rect1.centerx
          rect2 = perso_img.get_rect(midtop=(850, 50))
          x2 = rect2.centerx
          
          clock = pygame.time.Clock()
          
          dirty_rect1, dirty_rect2 = rect1.copy(), rect2.copy() #Anciennes positions à "nettoyer"
          dirty_rects = [dirty_rect1, dirty_rect2, rect1, rect2]
          
          run = True
          while run:
              millisecondes = clock.tick()
              secondes = millisecondes / 1000.0
              for event in pygame.event.get():
                  if event.type == QUIT:
                      run = False
                  elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                      run = False
                              
              # dx = 1.05 * dx #accélération
              dirty_rect1.center, dirty_rect2.center = rect1.center, rect2.center
              x1 += dx * secondes
              rect1.centerx = x1
              x2 += -dx * secondes
              rect2.centerx = x2
          
          
              if rect1.colliderect(rect2):
                  dx = 0
              
              # On blit les morceaux du background aux anciennes positions
              fenetre.blit(background, dirty_rect1, dirty_rect1)
              fenetre.blit(background, dirty_rect2, dirty_rect2)
              
              # On blit les personnages
              fenetre.blit(perso_img, rect1)
              fenetre.blit(perso_img, rect2)
              pygame.display.update(dirty_rects) #permet de n'actualiser qu'une partie de l'écran
          
          pygame.quit()
          
          • Partager sur Facebook
          • Partager sur Twitter
            26 mars 2015 à 23:00:50

            Ah oui, je comprend mieux ! Je ne voyais simplement pas comment blitter juste une partie du background... Car en effet, s'il nous reste du temps nous mettrons très certainement une image en background pour embellir le tout :)
            J'ai quelque peu modifié mon programme depuis le premier message afin d'intégrer les éléments de jeu que l'on souhaitais, mais je pense pouvoir appliquer les dirty_rects sans trop de difficultés.

            En tout cas ce projet m'as vraiment lancé dans pygame, moi qui ne connaissait pas python :) Et je peux dire que j'adore ça ;)

            Je reposterais si jamais on rencontre un problème que l'on arrive pas à résoudre, mais normalement le reste n'est que gestion du score et de l'interface... En somme plus long que difficile, ça devrait passer.

            • Partager sur Facebook
            • Partager sur Twitter

            [Pygame]Problème de mouvements de personnages

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown