Difference Between Pygame.Display.Update and Pygame.Display.Flip

Difference between pygame.display.update and pygame.display.flip

The main difference between pygame.display.flip and pygame.display.update is, that

  • display.flip() will update the contents of the entire display
  • display.update() allows to update a portion of the screen, instead of the entire area of the screen. Passing no arguments, updates the entire display

To tell PyGame which portions of the screen it should update (i.e. draw on your monitor) you can pass a single pygame.Rect object, or a sequence of them to the display.update() function. A Rect in PyGame stores a width and a height as well as a x- and y-coordinate for the position.

PyGame's built-in dawning functions and the .blit() method for instance return a Rect, so you can simply pass it to the display.update() function in order to update only the "new" drawn area.

Due to the fact that display.update() only updates certain portions of the whole screen in comparison to display.flip(), display.update() is faster in most cases.

Why is pygame.display.update() slower than pygame.display.flip()?

You must first understand how pygame.display.flip and pygame.display.update work.

When the screen mode pygame.DOUBLEBUF is set, Pygame actually maintains two screens: the active screen which is presently displayed and a buffer which you (the programmer) can update behind the scenes (without the user seeing anything).

Once you are done with your edits on the buffer, you can use pygame.display.flip to switch the active screen with the buffer. The entire screen is updated. This is the recommended way to update the entire screen. Also, this is the only way to update non-software screens (OPENGL and Hardware accelerated screens for example).

pygame.display.update on the other hand treats the screen as a group of pixels (that's called a software screen). This allows a Pygame program to update only a portion of the screen. This is faster as only a portion of the screen needs to be modified.

Now, if the entire screen is to be updated (pygame.display.flip and pygame.display.update without any arguments) pygame.display.flip is faster.

Remember, I said OpenGL and HW-accelerated screens (SOFT-screens too) maintain a buffer. Drawing to this buffer is slow, but flipping is very fast (in HW-screens and OpenGL). Updating the entire screen using pygame.display.update is even slower as it does things pixel by pixel and without HW-acceleration.

pygame.display.update updates the entire screen

When you are using pygame.display.update() there are two kinds of an optional argument, single rect (which defaults to None) and a list of rects. If no argument is passed, it updates the entire surface area - like display.flip() does.

update(rectangle=None) -> None
update(rectangle_list) -> None

To update only specific elements, either create a list of these elements if you want to update the same group at the same time

background_rects = [star_rect, star_rect, star_rect, some_other_rect]
foreground_rects = [player_rect, enemy1_rect, enemy2_rect, bullet1_rect, bullet2_rect]
pygame.display.update(background_rects)
pygame.display.update(foreground_rects)

or call update(rect) multiple times with the individual elements:

pygame.display.update(star1_rect)
pygame.display.update(star2_rect)
pygame.display.update(star3_rect)
pygame.display.update(character_rect)
pygame.display.update(enemy_rect)

Link to the documentation: https://www.pygame.org/docs/ref/display.html#pygame.display.update

There seems to be some (probably unintended as there is nothing about it in the docs) difference between the handling of pygame 1.9.6 and the 2.0.0.dev branches - below is a MRE which works with 1.9.6, but not with the 2.0.0.dev10 version. In 1.9.6 the difference in updating the display is easily visible. I suggest you install the stable 1.9.6 version if you need this exact functionality!

In case others want to try their luck, here is the MRE with which I tested:

import pygame
import time
screen = pygame.display.set_mode((720, 480))

rect = pygame.Rect((10, 50), (32, 32))
image = pygame.Surface((32, 32))
image.fill((0,100,0))

rect2 = pygame.Rect((10, 10), (32, 32))
image2 = pygame.Surface((32, 32))
image2.fill((100,100,0))

i = 0
while True:
i += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()

screen.blit(image, rect)
screen.blit(image2, rect2)
rect.x += 1 # we update the position every cycle
rect2.x += 1 # we update the position every cycle

# but update the rect on screen at different times:
if i < 10:
pygame.display.update() # both
elif i > 50 and i < 75:
pygame.display.update(rect2) # only rect2
elif i >= 100:
pygame.display.update(rect) # only rect

time.sleep(0.1)

Why is nothing drawn in PyGame at all?

You need to update the display.
You are actually drawing on a Surface object. If you draw on the Surface associated to the PyGame display, this is not immediately visible in the display. The changes become visibel, when the display is updated with either pygame.display.update() or pygame.display.flip().

See pygame.display.flip():

This will update the contents of the entire display.

While pygame.display.flip() will update the contents of the entire display, pygame.display.update() allows updating only a portion of the screen to updated, instead of the entire area. pygame.display.update() is an optimized version of pygame.display.flip() for software displays, but doesn't work for hardware accelerated displays.

The typical PyGame application loop has to:

  • handle the events by calling either pygame.event.pump() or pygame.event.get().
  • update the game states and positions of objects dependent on the input events and time (respectively frames)
  • clear the entire display or draw the background
  • draw the entire scene (draw all the objects)
  • update the display by calling either pygame.display.update() or pygame.display.flip()
  • limit frames per second to limit CPU usage with pygame.time.Clock.tick
import pygame
from pygame.locals import *
pygame.init()

DISPLAY = pygame.display.set_mode((800,800))
pygame.display.set_caption("thing")
clock = pygame.time.Clock()

run = True
while run:
# handle events
for event in pygame.event.get():
if event.type == QUIT:
run = False

# clear display
DISPLAY.fill(0)

# draw scene
pygame.draw.rect(DISPLAY, (200,200,200), pygame.Rect(0,400,800,400))

# update display
pygame.display.flip()

# limit frames per second
clock.tick(60)

pygame.quit()
exit()

Sample Image repl.it/@Rabbid76/PyGame-MinimalApplicationLoop See also Event and application loop

Performance between flip and update in pygame

Calling update after each blit will kill your performance. Just call update or flip once per frame at most.


If you're using an OPENGL or HWSURFACE, then you have to use flip, which updates the entire screen.


If you're using a software display (which is the default), using the update function offers the best performance; if you pass the function a list of rectangles so it only updates the portions of the screen that actually need to be updated (YMMV, depending on what you actually do and what hardware you use, but usually this is the way to go).

Pygame already makes it very easy to use by offering the DirtySprite and LayeredDirty classes.

Pygame: pygame.display.flip() slows down game considerably

Higher screen sizes result in lower framerates.

Of course, so if you don't have a super fast computer, consider reducing the size of your window.

Also, I think 1000x1000 is quite large for most of the screens... So try to reduce the size of your game, for example 900x500, or 640x480, then use the tag pygame.SCALED in addition of pygame.FULLSCREEN to resize the game window to your current screen size.

I'm using [...] pygame 1.9.3.

Consider updating your pygame version - When I updated pygame 1.9.6 to pygame 2.0.1, I litteraly doubled my framerate. (+ pygame 2.0.0 and newest releases fix tons of bugs, and add tons of new possibilities)

But if you want a high resolution and a good speed, I think pygame isn't enough. If you want to create games in general, consider using Unity for example.

pygame, screen not updating or filling with correct color

Upgrading to the most recent version of pygame fixed this.

pip3 install pygame --upgrade

thanks to @rabbid76 for the solution

Why does pygame.display.update() not work if an input is directly followed after it?

Call pygame.event.pump() after pygame.display.update() and before input(''):

def main():
pygame.draw.rect(screen,[235,235,235],(200,200,200,200))
pygame.display.update()

pygame.event.pump()

input('')

At some OS, pygame.display.update() respectively pygame.display.flip() doesn't update the display directly. It just invalidates the display and notifies the system to update the display. Actually the display is updated when the events are handled.

The events are either handled by either pygame.event.pump() or pygame.event.get() (Which is used in event loops, but would do the job as well). Note this instruction do not only handle the IO or user events, they handle a bunch of internal events too, which are required to run run the system.

Not all implementations on all OS behave the same. At some OS it is sufficient to call pygame.display.update(), that is the reason that not everyone at every system can reproduce the issue. But in this case it is never wrong to call pygame.event.pump().

Any way to speed up Python and Pygame?

Use Psyco, for python2:

import psyco
psyco.full()

Also, enable doublebuffering. For example:

from pygame.locals import *
flags = FULLSCREEN | DOUBLEBUF
screen = pygame.display.set_mode(resolution, flags, bpp)

You could also turn off alpha if you don't need it:

screen.set_alpha(None)

Instead of flipping the entire screen every time, keep track of the changed areas and only update those. For example, something roughly like this (main loop):

events = pygame.events.get()
for event in events:
# deal with events
pygame.event.pump()
my_sprites.do_stuff_every_loop()
rects = my_sprites.draw()
activerects = rects + oldrects
activerects = filter(bool, activerects)
pygame.display.update(activerects)
oldrects = rects[:]
for rect in rects:
screen.blit(bgimg, rect, rect)

Most (all?) drawing functions return a rect.

You can also set only some allowed events, for more speedy event handling:

pygame.event.set_allowed([QUIT, KEYDOWN, KEYUP])

Also, I would not bother with creating a buffer manually and would not use the HWACCEL flag, as I've experienced problems with it on some setups.

Using this, I've achieved reasonably good FPS and smoothness for a small 2d-platformer.

What is the difference between screen.blit(player, (xpos, ypos)) and display.flip() in pygame?

blit() doesn't update screen - it draws image in buffer.

update() and flip() sends buffer to video card which displays it on monitor.

If you have code with blit() but without update() or flip() then it will display nothing.


flip() sends all buffer to video card. Probably it can use optimized method to do it fast.

update() can get list with Rect() and sends only some part of buffer so it could be faster. But you have to know which parts you what to replace. Sometimes it is hard to correctly choose which areas to update.

See doc: update(), flip()


Sample Image



Related Topics



Leave a reply



Submit