开发者

Smooth movement of player in pygame

I'm using the pygame library. The following is pseudo code for my event handling for the player:

#generates multiple events for keys that are held down
pygame开发者_StackOverflow社区.key.set_repeat(30,30)

for event in pygame.event.get()

   nextPos = currentPos

   if(keyUp):
       if event.key == w :
         key_w = false
       #do the same for s, a and d

   if(keyDown):
       if event.key == w:
         key_w = true
       #same for s,a and d

   if(key_w):
      #update nextPos

   #do same for key_s, key_a and key_d

   currentPos = nextPos

The problem is that sometimes when I move my mouse on the screen, and I'm pressing a key at the same time, while processing the events of the mouse, the events of the key are queued up, and these multiple keypresses are executed together, so that the player seems to jump a huge distance.

This problem is not caused if I don't move the mouse at all.


Update to my answer:

I checked my game code to see how I handle keys every frame and it seems that I don't get key information from the events but use pygame.key.get_pressed():

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gl.loop_main_loop = False # exit main loop and terminate 
    keys = pygame.key.get_pressed()
    for key, state in enumerate(keys):
        if (key in self.key_handlers) and state:
            self.key_handlers[key]() # call key handler proc

That means that I only process each relevant key once per frame. The mouse can be read the way I describe below.

Just remember to use delta time in move vector calculation if your game doesn't have fixed frame rate.


Maybe the better idea is to during each process all keyboard event first and build your own key status representation, i.e. a structure which tell you which keys important to you (e.g. WSAD) are up or down. When all events have been processed in that frame, run you movement code using your key status data.

Do not use mousemotion events to track your mouse but read the position and buttons directly using pygame.mouse.get_pos() and pygame.mouse.get_pressed().

Your movement code should also take into account the fact that your game runs at variable frame rate (unless you forced pygame to keep the frame rate constant) and use time delta in your move vector calculations.


I use the following method...

I initialize the cooridinate variables...

x = 300
y = 300
pX = 0
pY = 0

In this case, x and y are the actual coordinates used by the player sprite, and pX and pY are used by the event handler.

Then I use the following code in the event handler...

for event in pygame.event.get(): 
    if event.type == pygame.QUIT: 
        sys.exit(0)

    if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
        pX -= 2
    if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
        pX += 2
    if event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
        pY -= 2
    if event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
        pY += 2       

    if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
        pX += 2
    if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
        pX -= 2
    if event.type == pygame.KEYUP and event.key == pygame.K_UP:
        pY += 2
    if event.type == pygame.KEYUP and event.key == pygame.K_DOWN:
        pY -= 2

Finally in the main game loop where the player's coordinates are handled, I put...

x += pX
y += pY


Maybe an event queue is not the best solution here, and instead, say, polling once per frame would be better?


I would not use pygame.event.get()

In my opinion, the best input for player movement pygame.key.get_pressed()

I would format it like this:

while True:
    keys = pygame.key.get_pressed()
    if keys[K_a]:
        player.pos.x -= 10
    if keys[K_d]:
        player.pos.x += 10
    if keys[K_w]:
        player.pos.y -= 10
    if keys[K_s]:
        player.pos.y += 10

This way the system will check for pressed down keys on every frame.


I can't test right now sadly but do this CODE:

import pygame, sys

clock = pygame.time.Clock()

playerX,playerY = 100,100 # Change 100 to the starting point you want
playerXc,playerYc = 0,0

while True:

    playerX += playerXc
    playerY += playerYc

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
     
        # Keydown Events
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_w:
                playerYc = 1 # Change value to the speed you would like also change it to -1 if it goes wrong direction

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                playerXc = -1 # Change value to the speed you would like to change and set it to 1 if it goes the wrong direction

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_s:
                playerYc = -1 # Change value to the speed you would like also change it to 1 if it goes the wrong direction

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_d:
                playerXc = 1 # Change value to the speed you would like to change and set it to -1 if it goes the wrong direction

        # Keyup Events
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_a:
                playerXc = 0

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_w:
                playerYc = 0

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_s:
                playerYc = 0

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_d:
                playerXc = 0

    
    pygame.display.update()
    clock.tick(60) # Change 60 to the framerate you would like so it runs smoother or the opposite.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜