18
\$\begingroup\$

I'm trying to develop a simple game made with Pygame (Python library).

I have a sprite object which's the player and I move it using arrow keys. If I don't move the mouse, the sprite moves normally, but when I move the mouse, the sprite moves faster (like x2 or x3). The player object is inside the charsGroup var.

I've run the game in W7 and in Ubuntu. Same thing happens in both OS.

I have more entities which move like NPCs and bullets but they don't get affected, just the player. Given this, I think that the problem maybe has a direct connection with the player moving system (arrow keys).

Here is the update() method of the player object:

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

And here is the while loop:

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

I don't know what more you can need to help me, but anything you need (more info or code) just ask for it!

\$\endgroup\$
4
  • 5
    \$\begingroup\$ Your exact bug actually exists in many applications. Try drag selecting in a large document and moving your cursor off the edge. Usually the program's edge scroll will kick in and slowly select more of the document. If you move your mouse from side to side it will usually scroll much faster, since their scroll speed is tied to their event loop, and the X motions wake up their event loop repeatedly. \$\endgroup\$ Commented May 21, 2015 at 16:31
  • 2
    \$\begingroup\$ @BenJackson I find that to be a useful bug when the scrolling is horribly slow to begin with. \$\endgroup\$ Commented May 22, 2015 at 0:10
  • 1
    \$\begingroup\$ This is unrelated to your bug, but I would recommend loading the image one time, and storing it in an object. BULLET_IMAGE = pygame.image.load("bullet.png") and then later on self.bulletsGroup.add(Bullet(BULLET_IMAGE... \$\endgroup\$
    – DJMcMayhem
    Commented May 23, 2015 at 16:00
  • \$\begingroup\$ @DJMcMayhem You're totally right, I've done it with the rest of images but I missed do it with this.. thanks! :) \$\endgroup\$
    – Drumnbass
    Commented May 23, 2015 at 18:12

2 Answers 2

43
\$\begingroup\$

tl;dr don't mix your event loop with your game loop.

When you move your mouse, the game receives a load of pygame.MOUSEMOTION events. You don't actually use these events to update your mouse position though, you are getting the current state of the mouse using pygame.mouse.get_pos(). That's inefficient, but it's not the problem.

The problem is you are updating the player position inside the event loop!

This is what's supposed to happen:

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

This is what your code does:

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

When you move your mouse, the event loop will execute many times per frame. But when you check which keys are pressed with pygame.key.get_pressed(), they stay pressed until you let go, some time later. So as your event loop is churning through the mouse move events, it will re-apply the player moves repeatedly.

The solution is simple: move the player outside the event loop.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Thanks! It works perfectly now and probably I had never realize what was happening! Btw, why do you say that pygame.mouse.get_pos() is inefficient? What alternatives do I have? \$\endgroup\$
    – Drumnbass
    Commented May 22, 2015 at 17:13
  • \$\begingroup\$ @Drumnbass pygame.mouse.get_pos() gets the latest position of the mouse, regardless of the event queue, so there is no need to put it inside the event loop. The alternative would be to process every pygame.MOUSEMOTION yourself, but unless you need every event (e.g. you are writing a painting program), the latest position will do. \$\endgroup\$ Commented May 26, 2015 at 7:19
4
\$\begingroup\$

Here are some more thoughts to complement the existing answer.

Gaffer On Games has a great article on game loops that has been referenced everywhere.

Your game loop should have different independent stages: Input, Update, Render.

You could for example read inputs 30 times per second (or in real-time for better responsiveness), do 30 updates per second and render 60 frames per second, or whatever values work well for your game.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .