¿Por qué mi jugador de sprites se mueve más rápido cuando muevo el mouse?

17

Estoy tratando de desarrollar un juego simple hecho con Pygame (biblioteca de Python).

Tengo un spriteobjeto que es el playery lo muevo usando las teclas de flecha. Si no muevo el mouse, el sprite se mueve normalmente, pero cuando muevo el mouse, el sprite se mueve más rápido (como x2 o x3). El playerobjeto está dentro de la charsGroupvar.

Ejecuté el juego en W7 y en Ubuntu. Lo mismo sucede en ambos sistemas operativos.

Tengo más entidades que se mueven como NPC y balas, pero no se ven afectadas, solo el jugador. Dado esto, creo que el problema puede tener una conexión directa con el sistema de movimiento del jugador (teclas de flecha).

Aquí está el update()método del playerobjeto:

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

Y aquí está el 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() 

No sé qué más puede necesitar para ayudarme, pero cualquier cosa que necesite (más información o código) ¡solo pídala!

Tambor y bajo
fuente
55
Su error exacto realmente existe en muchas aplicaciones. Intente arrastrar seleccionando en un documento grande y moviendo el cursor fuera del borde. Por lo general, el desplazamiento del borde del programa se activará y seleccionará lentamente más del documento. Si mueve el mouse de lado a lado, generalmente se desplazará mucho más rápido, ya que su velocidad de desplazamiento está vinculada a su bucle de eventos, y los movimientos X despiertan su bucle de eventos repetidamente.
Ben Jackson
2
@BenJackson Creo que es un error útil cuando el desplazamiento es terriblemente lento para empezar.
user253751
1
Esto no está relacionado con su error, pero recomendaría cargar la imagen una vez y almacenarla en un objeto. BULLET_IMAGE = pygame.image.load("bullet.png")y luegoself.bulletsGroup.add(Bullet(BULLET_IMAGE...
DJMcMayhem
@DJMcMayhem Tienes toda la razón, lo hice con el resto de las imágenes, pero me perdí hacerlo con esto ... ¡gracias! :)
Drumnbass

Respuestas:

43

tl; dr no mezcle su bucle de eventos con su bucle de juego .

Cuando mueves el mouse, el juego recibe una gran cantidad de pygame.MOUSEMOTIONeventos. Sin embargo, en realidad no utiliza estos eventos para actualizar la posición del mouse, está obteniendo el estado actual del mouse pygame.mouse.get_pos(). Eso es ineficiente, pero no es el problema.

¡El problema es que estás actualizando la posición del jugador dentro del bucle de eventos !

Esto es lo que se supone que debe suceder:

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

Esto es lo que hace tu código:

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

Cuando mueve el mouse, el bucle de eventos se ejecutará muchas veces por cuadro. Pero cuando verifica con qué teclas se presionan pygame.key.get_pressed(), permanecen presionadas hasta que lo suelta, algún tiempo después. Entonces, a medida que su ciclo de eventos se agita a través de los eventos de movimiento del mouse, volverá a aplicar los movimientos del jugador repetidamente.

La solución es simple: mover al jugador fuera del ciclo de eventos.

congusbongus
fuente
1
¡Gracias! ¡Funciona perfectamente ahora y probablemente nunca me había dado cuenta de lo que estaba sucediendo! Por cierto, ¿por qué dices que pygame.mouse.get_pos()es ineficiente? ¿Qué alternativas tengo?
Drumnbass
Hola, @congusbongus, ¿podrías explicarme eso? Gracias.
Drumnbass
@Tambor y bajo pygame.mouse.get_pos() obtiene la última posición del mouse, independientemente de la cola del evento, por lo que no es necesario ponerlo dentro del bucle de eventos. La alternativa sería procesar cada pygame.MOUSEMOTIONuno usted mismo, pero a menos que necesite cada evento (por ejemplo, si está escribiendo un programa de pintura), la última posición lo hará.
congusbongus
3

Aquí hay algunos pensamientos más para complementar la respuesta existente .

Gaffer On Games tiene un gran artículo sobre bucles de juegos que se ha mencionado en todas partes.

Su ciclo de juego debe tener diferentes etapas independientes: Entrada, Actualización, Render.

Podría, por ejemplo, leer entradas 30 veces por segundo (o en tiempo real para una mejor capacidad de respuesta), hacer 30 actualizaciones por segundo y renderizar 60 cuadros por segundo, o cualquier valor que funcione bien para su juego.

HgMerk
fuente