Search code examples
pythonoptimizationgraphicspygamesystem.drawing

How to draw to an off-screen display in PyGame


I'm doing a graphics test using PyGame to simulate the Dragon Curve being unfolded. I already made one successful version that keeps track of all the points as they rotate around each other, but obviously, this begins to slow down pretty substantially after a few iterations. In order to speed this up, I want to simply store the drawn segments into an image variable, and continually save a segment of the screen to a variable and draw those moving rather than keeping track of a lot of points. How can I do either of the following?

  • Draw to an off-screen image variable that then gets drawn to the screen in the correct place
  • Save a section of the visible display into an image variable

I tried reading through some of the PyGame documentation, but I didn't have any success.

Thanks!


Solution

  • Creating an additional surface object, and drawing to it is the solution. This surface object can then be drawn onto the display's surface object as shown below.

    More information on the PyGame Surface object can be found here

    import pygame, sys
    
    SCREEN_SIZE = (600, 400)
    BG_COLOR = (0, 0, 0)
    LINE_COLOR = (0, 255, 0)
    pygame.init()
    clock = pygame.time.Clock() # to keep the framerate down
    
    image1 = pygame.Surface((50, 50))
    image2 = pygame.Surface((50, 50))
    image1.set_colorkey((0, 0, 0)) # The default background color is black
    image2.set_colorkey((0, 0, 0)) # and I want drawings with transparency
    
    screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
    screen.fill(BG_COLOR)
    
    # Draw to two different images off-screen
    pygame.draw.line(image1, LINE_COLOR, (0, 0), (49, 49))
    pygame.draw.line(image2, LINE_COLOR, (49, 0), (0, 49))
    
    # Optimize the images after they're drawn
    image1.convert()
    image2.convert()
    
    # Get the area in the middle of the visible screen where our images would fit
    draw_area = image1.get_rect().move(SCREEN_SIZE[0] / 2 - 25,
                                       SCREEN_SIZE[1] / 2 - 25)
    
    # Draw our two off-screen images to the visible screen
    screen.blit(image1, draw_area)
    screen.blit(image2, draw_area)
    
    # Display changes to the visible screen
    pygame.display.flip()
    
    # Keep the window from closing as soon as it's finished drawing
    # Close the window gracefully upon hitting the close button
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit(0)
        clock.tick(30)