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!
2 Answers 2
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.
-
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– Drumnbass2015年05月22日 17:13:13 +00:00Commented 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 everypygame.MOUSEMOTION
yourself, but unless you need every event (e.g. you are writing a painting program), the latest position will do. \$\endgroup\$congusbongus– congusbongus2015年05月26日 07:19:54 +00:00Commented May 26, 2015 at 7:19
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.
BULLET_IMAGE = pygame.image.load("bullet.png")
and then later onself.bulletsGroup.add(Bullet(BULLET_IMAGE...
\$\endgroup\$