Pygame Screen breaks when moving line across screen
I am trying to move this image:
On my PyGame screen, right to left and back again. However, as the image moves, every second or so, I get screen tearing flickering, making its way like this:
The code I'm using is a loop like this:
screen.blit(img, (x,y))
pygame.update((x,y),(w,h))
pygame.draw.rect(screen,(0,0,0),((x,y),(w,h)))
So far I have tried to solve the following problem:
Using flags HWSURFACE
, FULLSCREEN
, DOUBLEBUF
when you create a screen, it is not affected, I also adjusted my .update(rect)
on .flip()
(as it is recommended for use DOUBLEBUF
?)
Sharing memory between GPU and CPU (I'm running this on a raspberry pi 2), I tried to give both more memory and no change.
Setting clock.tick to throttle the refresh rate to 60 FPS (higher and lower), this ironed out some of the tearing, but not all
Adjusting the size of each increment to the left or right, making smaller increments, results in less tearing, but also less speed. (Can't be too slow)
Blitting a new black surface instead of drawing a black rectangle over the previous position (while moving the image to make sure there is no trace behind it) when I read somewhere, which is blit
better supported HWSURFACE
than painting, although I can't confirm it? - It had no effect
If anyone has other solutions that can improve the situation, I would be grateful.
I would rather not switch from PyGame to anything else (like pyglet) as I've used quite a few PyGame implementations so far, but I'm open to suggestions.
Greetings
EDIT
Relevant code as requested:
if scanner == True:
clocker.tick(clockspeed)
if x < 11:
slower = 3
if firstTime == True:
img.set_alpha(int(x * 25))
newSurf.set_alpha(int(x * 25))
screen.blit(newSurf,(xText,35))
pygame.display.update((xText,35),((xText + newSurf.get_width()),(50 + newSurf.get_height())))
img.set_alpha(255)
elif x > (divider - 15):
slower = 3
else:
slower = 0
firstTime = False
screen.blit(img, ((xStart - (x * increment) + slower),100))
pygame.display.update(((xStart - (x * increment) + slower),100),(95,450))
pygame.draw.rect(screen, (0,0,0), (((xStart - (x * increment) + slower),100),(95,450)))
The variable slower
should provide a sense of inertia as the boom reaches the far left and right sides of its sweep at a speed that it will slow down slightly.
The variable is firstTime
meant to fade in the panel when it first appears.
There is another loop just below this that is very similar, but views the image in reverse.
this break is simply the result of displaying the screen. The next position for the line is rendering, while the previous position is being drawn. If the refresh rate and screen refresh rate are synchronous, this problem goes away. But since this is almost impossible to do accurately, I would suggest that you have your program take the path that the PICO-8 controls, waiting for the screen refresh to complete before changing the screen buffer to prevent tearing. I'm not sure if there is a method to wait for the screen refresh to complete, but if there is, the sequence should go:update back buffer → wait for screen to stop being drawn → flip buffers → screen is drawn again
Refreshing is when the screen is drawn from left to right, top to bottom, pixel by pixel. This is because the triple bus-to-screen connection only allows the brightness for one pixel at a time to come from the screen memory, so each one is drawn sequentially. The gap comes from the memory changing halfway through the update, so the line moves halfway down the screen.