Pourquoi mon joueur de sprite se déplace-t-il plus rapidement lorsque je déplace la souris?

17

J'essaie de développer un jeu simple fait avec Pygame (bibliothèque Python).

J'ai un spriteobjet qui est le playeret je le déplace à l'aide des touches fléchées. Si je ne déplace pas la souris, l'image-objet se déplace normalement, mais lorsque je déplace la souris, l'image-objet se déplace plus rapidement (comme x2 ou x3). L' playerobjet est à l'intérieur de la charsGroupvar.

J'ai exécuté le jeu dans W7 et dans Ubuntu. La même chose se produit dans les deux systèmes d'exploitation.

J'ai plus d'entités qui se déplacent comme des PNJ et des balles mais elles ne sont pas affectées, juste le joueur. Compte tenu de cela, je pense que le problème a peut-être une connexion directe avec le système de déplacement du joueur (touches fléchées).

Voici la update()méthode de l' playerobjet:

def update(self):

    for event in pygame.event.get():
        key = pygame.key.get_pressed()
        mouseX, mouseY = pygame.mouse.get_pos()
        if event.type == pygame.MOUSEBUTTONDOWN:
            self.bulletsGroup.add(Bullet(pygame.image.load("bullet.png"),
                                          self.rect.x + (self.image.get_width()/2),
                                           self.rect.y + (self.image.get_height()/2),
                                            mouseX, mouseY, 50, 50))

        if key[pygame.K_RIGHT]:
            if not self.checkCollision():
                self.rect.x += 10
            else:
                self.rect.x -= 10
        if key[pygame.K_LEFT]:
            if not self.checkCollision():
                self.rect.x -= 10
            else:
                self.rect.x += 10
        if key[pygame.K_UP]:
            if not self.checkCollision():
                self.rect.y -= 10
            else:
                self.rect.y += 10
        if key[pygame.K_DOWN]:
            if not self.checkCollision():
                self.rect.y += 10
            else:
                self.rect.y -= 10

Et voici la boucle while:

while True:

    if PLAYER.healthBase <= 0:
        GAMEOVER = True

    if not GAMEOVER:
        mapTilesGroup.draw(SCREEN)
        charsGroup.update()
        charsGroup.draw(SCREEN)
        npcsGroup.update()
        npcsGroup.draw(SCREEN)
        drawBullets()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

    if GAMEOVER:
        myfont = pygame.font.SysFont("monospace", 30)
        label = myfont.render("GAME OVER!", 1, (255, 255, 0))
        SCREEN.blit(label, (400, 300))

    freq.tick(0)

    pygame.display.flip() 

Je ne sais pas de quoi vous avez besoin pour m'aider, mais tout ce dont vous avez besoin (plus d'informations ou de code), demandez-le!

Drumnbass
la source
5
Votre bug exact existe en fait dans de nombreuses applications. Essayez de faire glisser la sélection dans un grand document et de déplacer votre curseur hors du bord. Habituellement, le défilement des bords du programme démarre et sélectionne lentement une plus grande partie du document. Si vous déplacez votre souris d'un côté à l'autre, elle défilera généralement beaucoup plus rapidement, car leur vitesse de défilement est liée à leur boucle d'événements et les mouvements X réveillent leur boucle d'événements à plusieurs reprises.
Ben Jackson
2
@BenJackson Je trouve que c'est un bug utile lorsque le défilement est horriblement lent au début.
user253751
1
Ceci n'est pas lié à votre bug, mais je recommanderais de charger l'image une fois et de la stocker dans un objet. BULLET_IMAGE = pygame.image.load("bullet.png")puis plus tardself.bulletsGroup.add(Bullet(BULLET_IMAGE...
DJMcMayhem
@DJMcMayhem Vous avez tout à fait raison, je l'ai fait avec le reste des images mais j'ai manqué de le faire avec ça .. merci! :)
Drumnbass

Réponses:

42

tl; dr ne mélangez pas votre boucle d'événement avec votre boucle de jeu .

Lorsque vous déplacez votre souris, le jeu reçoit une charge d' pygame.MOUSEMOTIONévénements. Cependant, vous n'utilisez pas ces événements pour mettre à jour la position de votre souris, vous obtenez l'état actuel de la souris en utilisant pygame.mouse.get_pos(). C'est inefficace, mais ce n'est pas le problème.

Le problème est que vous mettez à jour la position du joueur dans la boucle d'événement !

C'est ce qui est censé se produire:

game loop:
    event loop # get key presses, mouse moves etc.)
    if key pressed in the event loop:
        move the player

Voici ce que fait votre code:

game loop:
    event loop:
        if key pressed:
            move the player

Lorsque vous déplacez votre souris, la boucle d'événements s'exécute plusieurs fois par image. Mais lorsque vous vérifiez avec quelles touches vous appuyez pygame.key.get_pressed(), elles restent enfoncées jusqu'à ce que vous les relâchiez, quelque temps après. Ainsi, pendant que votre boucle d'événement passe à travers les événements de déplacement de la souris, elle réappliquera les mouvements du joueur à plusieurs reprises.

La solution est simple: déplacer le joueur hors de la boucle d'événement.

congusbongus
la source
1
Merci! Cela fonctionne parfaitement maintenant et je n'avais probablement jamais réalisé ce qui se passait! Btw, pourquoi dites-vous que pygame.mouse.get_pos()c'est inefficace? Quelles alternatives ai-je?
Drumnbass
Bonjour @congusbongus, pourriez-vous m'expliquer cela? Merci.
Drumnbass
@Drumnbass pygame.mouse.get_pos()obtient la dernière position de la souris, quelle que soit la file d'attente des événements, il n'est donc pas nécessaire de la placer dans la boucle d'événements. L'alternative serait de traiter tout pygame.MOUSEMOTIONvous-même, mais à moins que vous n'ayez besoin de chaque événement (par exemple, vous écrivez un programme de peinture), la dernière position fera l'affaire.
congusbongus
3

Voici quelques réflexions supplémentaires pour compléter la réponse existante .

Gaffer On Games a un excellent article sur les boucles de jeu qui a été référencé partout.

Votre boucle de jeu doit avoir différentes étapes indépendantes: entrée, mise à jour, rendu.

Vous pouvez par exemple lire les entrées 30 fois par seconde (ou en temps réel pour une meilleure réactivité), faire 30 mises à jour par seconde et afficher 60 images par seconde, ou toutes les valeurs qui fonctionnent bien pour votre jeu.

HgMerk
la source