Pygame - time and movement issues

Started by
1 comment, last by Oluseyi 8 years, 8 months ago

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

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?

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.

This topic is closed to new replies.

Advertisement