Jump to content
  • Advertisement
Sign in to follow this  
Don Polettone

Pygame - time and movement issues

This topic is 1145 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi there,

 

I've been trying very hard to get smooth movement using Pygame, but no matter how I try, things always look a bit jiggly.

 

I've read many tutorials about time step and pygame's time module, but it did not help. I would basically like to create pixely, "NES-ish" games and have therefore chosen a fixed time step of about 16 ms (= ca. 60 FPS). I've written a little demo program to test the main loop and see if it runs smooth, but the movement seems to stutter a bit sometimes. The module should run standalone with just Python 2.x and Pygame installed. Press ESC to exit the demo. Here it is:

 

import sys
import pygame
pygame.init()
from pygame.constants import FULLSCREEN
from pygame.rect import Rect

RES = (640, 480)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
FPS = 60

screen = pygame.display.set_mode(RES, FULLSCREEN)
clock = pygame.time.Clock()
font = pygame.font.SysFont(pygame.font.get_default_font(), 24)

player_pos = [0.0, 240.0]
player_rect = Rect((0, 0), (40, 40))
player_speed = 0.8 # pixels per frame

def check_quit():

    for event in pygame.event.get():
        quit_it = (event.type == pygame.QUIT or
                   (event.type == pygame.KEYDOWN and
                    event.key == pygame.K_ESCAPE))
        if quit_it:
            pygame.quit()
            sys.exit()

def draw_player():

    pygame.draw.rect(screen, RED, player_rect)

def draw_fps(ms):

    topleft = (20, 20)
    surf = font.render("FPS " + str(ms), True, WHITE)
    screen.blit(surf, topleft)

def draw_time_left(ms):

    topleft = (20, 50)
    surf = font.render("time left " + str(ms), True, WHITE)
    screen.blit(surf, topleft)

def main():

    time_left = 0
    fps = FPS
    player_rect.center = player_pos
    draw_player()
    pygame.display.flip()
    pygame.time.wait(4000)
    
    while 1:
        check_quit()
        screen.fill(BLACK)
        player_pos[0] += player_speed
        player_rect.center = player_pos
        draw_player()
        draw_time_left(time_left)
        draw_fps(fps)
        pygame.display.flip()
        frame_duration = clock.tick(FPS) # 1 frame -> ca. 16 milsecs
        time_used = clock.get_rawtime() # cpu time used for 1 frame
        fps = clock.get_fps() # fps computed by pygame
        time_left = frame_duration - time_used # time left for each frame to compute more stuff
        
if __name__ == "__main__":
    main()

 

Are there any experienced pygame users who could run the file and see if they experience the same? I really start thinking that pygame is not the proper tool to code my stuff...

 

Thanks, folks

Share this post


Link to post
Share on other sites
Advertisement
Never programmed in pyGame, but I did use the underlying SDL1 library, and one thing I know is that it wants multiples of 10msecs. Did you try other rates to see if that fixes your stutter problem?

Share this post


Link to post
Share on other sites

Unfortunately I can't run your demo because PyGame on OS X relies on X11, which I won't install, and my Linux box is temporarily out of commission. Nevertheless, I know what your problem is.
 

I've been trying very hard to get smooth movement using Pygame, but no matter how I try, things always look a bit jiggly.
 
I've read many tutorials about time step and pygame's time module, but it did not help. I would basically like to create pixely, "NES-ish" games and have therefore chosen a fixed time step of about 16 ms (= ca. 60 FPS). I've written a little demo program to test the main loop and see if it runs smooth, but the movement seems to stutter a bit sometimes.

 

In your main loop, you do two things. You update the player position:

        player_pos[0] += player_speed
        player_rect.center = player_pos

and you update the frame time, setting an upper bound on refresh frequency:

        frame_duration = clock.tick(FPS) # 1 frame -> ca. 16 milsecs

The former assumes that frame_duration is constant, so it uses a constant increment for player position. The latter obtains the actual duration of the frame, which the PyGame docs tell us: "Note that this function uses SDL_Delay function which is not accurate on every platform…"

 

Your problem is that you are applying what you think is a constant displacement per constant time, yielding constant velocity, but in actuality your time is variable, making your velocity variable. To smooth it out, normalize your displacement by your actual frame time:

FPS = 60
player_speed = 0.8 # pixels per frame
basis_frame_time = 1.0 / FPS

while 1:
    # ...
    frame_duration = clock.tick(FPS)
    frame_displacement = player_speed * (frame_duration / basis_frame_time)
    player_pos[0] += frame_displacement
    #...

That should do it.

Edited by Oluseyi
Formatting

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!