Warum bewegt sich mein Sprite-Player schneller, wenn ich die Maus bewege?

17

Ich versuche ein einfaches Spiel mit Pygame (Python-Bibliothek) zu entwickeln.

Ich habe ein spriteObjekt, playerund ich bewege es mit den Pfeiltasten. Wenn ich die Maus nicht bewege, bewegt sich das Sprite normal, aber wenn ich die Maus bewege, bewegt sich das Sprite schneller (wie x2 oder x3). Das playerObjekt befindet sich im charsGroupvar.

Ich habe das Spiel in W7 und in Ubuntu ausgeführt. Das Gleiche passiert in beiden Betriebssystemen.

Ich habe mehr Wesen, die sich wie NPCs und Kugeln bewegen, aber sie werden nicht beeinflusst, nur der Spieler. In Anbetracht dessen denke ich, dass das Problem möglicherweise eine direkte Verbindung mit dem Bewegungssystem des Players (Pfeiltasten) hat.

Hier ist die update()Methode des playerObjekts:

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

Und hier ist die while-Schleife:

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() 

Ich weiß nicht, was Sie noch brauchen können, um mir zu helfen, aber alles, was Sie brauchen (mehr Informationen oder Code), fragen Sie einfach danach!

Schlagzeug und Bass
quelle
5
Ihr genauer Fehler existiert tatsächlich in vielen Anwendungen. Ziehen Sie die Auswahl in einem großen Dokument und bewegen Sie den Cursor vom Rand weg. Normalerweise springt der Bildlauf des Programms ein und wählt langsam einen größeren Teil des Dokuments aus. Wenn Sie die Maus von einer Seite zur anderen bewegen, wird der Bildlauf in der Regel viel schneller ausgeführt, da die Bildlaufgeschwindigkeit an die Ereignisschleife gebunden ist und die X-Bewegungen die Ereignisschleife wiederholt aktivieren.
Ben Jackson
2
@BenJackson Ich finde, dass dies ein nützlicher Fehler ist, wenn das Scrollen zunächst schrecklich langsam ist.
user253751
1
Dies hat nichts mit Ihrem Fehler zu tun, aber ich würde empfehlen, das Bild einmal zu laden und in einem Objekt zu speichern. BULLET_IMAGE = pygame.image.load("bullet.png")und dann späterself.bulletsGroup.add(Bullet(BULLET_IMAGE...
DJMcMayhem
@DJMcMayhem Du hast vollkommen recht, ich habe es mit dem Rest der Bilder gemacht, aber ich habe es verpasst, dies zu tun .. danke! :)
Drumnbass

Antworten:

43

tl; dr nicht mischen Ihre Ereignisschleife mit Ihrem Spiel Schleife .

Wenn Sie Ihre Maus bewegen, erhält das Spiel eine Menge pygame.MOUSEMOTIONEreignisse. Sie verwenden diese Ereignisse jedoch nicht, um Ihre Mausposition zu aktualisieren, sondern um den aktuellen Status der Maus zu ermitteln pygame.mouse.get_pos(). Das ist ineffizient, aber es ist nicht das Problem.

Das Problem ist, dass Sie die Spielerposition in der Event-Schleife aktualisieren !

Folgendes soll passieren:

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

So funktioniert Ihr Code:

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

Wenn Sie die Maus bewegen, wird die Ereignisschleife mehrmals pro Frame ausgeführt. Wenn Sie jedoch überprüfen, mit welchen Tasten Sie gedrückt sind pygame.key.get_pressed(), bleiben diese gedrückt, bis Sie einige Zeit später loslassen. Während Ihre Ereignisschleife die Mausbewegungsereignisse durchläuft, werden die Spielerbewegungen wiederholt angewendet.

Die Lösung ist einfach: Bewegen Sie den Player außerhalb der Ereignisschleife.

congusbongus
quelle
1
Vielen Dank! Es funktioniert jetzt perfekt und wahrscheinlich hatte ich nie gemerkt, was los war! Übrigens, warum pygame.mouse.get_pos()ist das ineffizient? Welche Alternativen habe ich?
Drumnbass
Hallo @congusbongus, kannst du mir das erklären? Vielen Dank.
Drumnbass
@Drumnbass ruft pygame.mouse.get_pos()unabhängig von der Ereigniswarteschlange die aktuelle Position der Maus ab, sodass Sie sie nicht in die Ereignisschleife einfügen müssen. Die Alternative wäre, jeden pygame.MOUSEMOTIONselbst zu bearbeiten, aber wenn Sie nicht jedes Ereignis benötigen (z. B. wenn Sie ein Malprogramm schreiben), reicht die letzte Position aus.
Congusbongus
3

Hier sind einige weitere Gedanken, die die bestehende Antwort ergänzen .

Gaffer On Games hat einen großartigen Artikel über Game Loops , auf den überall verwiesen wurde.

Ihre Spielrunde sollte verschiedene unabhängige Phasen haben: Eingabe, Aktualisierung, Rendern.

Sie können beispielsweise Eingaben 30-mal pro Sekunde lesen (oder in Echtzeit, um eine bessere Reaktionszeit zu erzielen), 30 Aktualisierungen pro Sekunde durchführen und 60 Bilder pro Sekunde rendern, oder welche Werte auch immer für Ihr Spiel gut geeignet sind.

HgMerk
quelle