Perché il mio lettore sprite si muove più velocemente quando muovo il mouse?


17

Sto cercando di sviluppare un semplice gioco realizzato con Pygame (libreria Python).

Ho un spriteoggetto che è il playere lo sposto usando i tasti freccia. Se non muovo il mouse, lo sprite si sposta normalmente, ma quando sposto il mouse, lo sprite si sposta più velocemente (come x2 o x3). L' playeroggetto è all'interno della charsGroupvar.

Ho eseguito il gioco in W7 e Ubuntu. La stessa cosa accade in entrambi i sistemi operativi.

Ho più entità che si muovono come NPC e proiettili ma non vengono colpite, solo il giocatore. Detto questo, penso che il problema abbia forse una connessione diretta con il sistema di spostamento del giocatore (tasti freccia).

Ecco il update()metodo playerdell'oggetto:

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

Ed ecco il ciclo 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() 

Non so di cosa tu possa aver bisogno per aiutarmi, ma qualsiasi cosa ti serva (maggiori informazioni o codice) basta chiedere!


5
Il tuo bug esatto esiste in realtà in molte applicazioni. Prova a trascinare selezionando in un documento di grandi dimensioni e spostando il cursore dal bordo. Di solito lo scorrimento del bordo del programma si avvia e seleziona lentamente più parte del documento. Se muovi il mouse da un lato all'altro, di solito scorrerà molto più velocemente, poiché la loro velocità di scorrimento è legata al loro loop degli eventi e i movimenti X attivano ripetutamente il loro loop degli eventi.
Ben Jackson,

2
@BenJackson Trovo che sia un bug utile quando lo scorrimento è orribilmente lento all'inizio.
user253751

1
Questo non è correlato al tuo bug, ma ti consiglio di caricare l'immagine una volta e di memorizzarla in un oggetto. BULLET_IMAGE = pygame.image.load("bullet.png")e poi più tardiself.bulletsGroup.add(Bullet(BULLET_IMAGE...
DJMcMayhem

@DJMcMayhem Hai perfettamente ragione, l'ho fatto con il resto delle immagini ma mi è mancato farlo con questo .. grazie! :)
Drumnbass,

Risposte:


43

tl; dr non mescolare il loop degli eventi con il loop del gioco .

Quando sposti il ​​mouse, il gioco riceve un sacco di pygame.MOUSEMOTIONeventi. In realtà non si utilizzano questi eventi per aggiornare la posizione del mouse, ma si sta utilizzando lo stato corrente del mouse pygame.mouse.get_pos(). Questo è inefficiente, ma non è il problema.

Il problema è che stai aggiornando la posizione del giocatore all'interno del loop degli eventi !

Questo è ciò che dovrebbe accadere:

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

Ecco cosa fa il tuo codice:

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

Quando sposti il ​​mouse, il loop degli eventi verrà eseguito più volte per frame. Ma quando controlli quali tasti vengono premuti pygame.key.get_pressed(), rimangono premuti fino a quando non lo lasci andare, qualche tempo dopo. Quindi, mentre il tuo loop degli eventi si muove tra gli eventi di spostamento del mouse, riapplicherà le mosse del giocatore ripetutamente.

La soluzione è semplice: sposta il giocatore fuori dal loop degli eventi.


1
Grazie! Funziona perfettamente ora e probabilmente non avevo mai realizzato cosa stesse succedendo! A proposito, perché dici che pygame.mouse.get_pos()è inefficiente? Quali alternative ho?
Drumnbass,

Ehilà @congusbongus, potresti spiegarmelo? Grazie.
Drumnbass,

@Drumnbass pygame.mouse.get_pos()ottiene l'ultima posizione del mouse, indipendentemente dalla coda degli eventi, quindi non è necessario inserirlo nel ciclo degli eventi. L'alternativa sarebbe quella di elaborare tutti pygame.MOUSEMOTIONvoi stessi, ma a meno che non abbiate bisogno di tutti gli eventi (ad esempio se state scrivendo un programma di pittura), l'ultima posizione lo farà.
congusbongus,

3

Ecco alcuni altri pensieri per integrare la risposta esistente .

Gaffer On Games ha un ottimo articolo sui loop di gioco a cui è stato fatto riferimento ovunque.

Il tuo loop di gioco dovrebbe avere diversi livelli indipendenti: input, aggiornamento, rendering.

Ad esempio, potresti leggere gli input 30 volte al secondo (o in tempo reale per una migliore reattività), fare 30 aggiornamenti al secondo e renderizzare 60 frame al secondo, o qualunque valore funzioni bene per il tuo gioco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.