0

I understand it is not possible to have multiple windows in Pygame: Multiple Displays in Pygame

However is it possible to have multiple display objects, only one of which is actually displayed to the user?

For example, suppose I have the following code, which displays 2 green circles and 2 red triangles:

import pygame

WIDTH, HEIGHT = 800, 600
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
FPS = 60
BLACK = (0, 0, 0)
GREEN = (0, 128, 0)
RED = (255, 0, 0)


def draw_window():

    # Set display background
    WIN.fill(BLACK)  
    
    # Draw shapes
    pygame.draw.circle(surface=WIN, center=(400, 300), radius=20, color=GREEN)
    pygame.draw.polygon(surface=WIN, points=((410, 270), (460, 320), (390, 290)), color=RED)
    pygame.draw.circle(surface=WIN, center=(200, 150), radius=30, color=GREEN)
    pygame.draw.polygon(surface=WIN, points=((180, 190), (200, 140), (190, 270)), color=RED)
    
    # Update display
    pygame.display.update() 


def main():

    clock = pygame.time.Clock()
    run = True
    while run:
        clock.tick(FPS)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        draw_window()

enter image description here

If I want to export the pixel data to a numpy array, and count the occurrences of each colour, I can do so with pygame.surfarray.pixels2d and np.unique:

data = pygame.surfarray.pixels2d(WIN)
unique, counts = np.unique(data, return_counts=True)
print(dict(zip(unique, counts)))

Which returns the pixel count of each colour:

{0: 474303, 32768: 3380, 16711680: 2317}

However suppose I want to count the number of pixels of each of the 4 shapes (rather than each of the colours displayed to the user), I could simply assign each shape a unique colour, for example in the code below, which would give me what I need (i.e. pixel count for each of the 4 shapes). But in doing so, I've displayed the 'wrong' colours to the user (i.e. they should seeing green and red only, not green red, yellow and blue).

Is it possible to create separate 'hidden' versions of the drawing (e.g. with different colours for the purpose of analysis), which are kept separate from the user's display? I understand I can't have multiple windows in Pygame, but I'm wondering if it's still possible to create multiple display objects - only one of which is actually shown to the user?

I imagine a workaround might be to draw each 'hidden' version for a single frame only (i.e. while I export to a numpy array), however this does not seem like a very elegant solution. The user might notice a sudden 'flash' while the hidden drawing is displayed temporarily, which would be a poor user experience.

Is there a better way to do this?

import pygame
import numpy as np

WIDTH, HEIGHT = 800, 600
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
FPS = 60


BLACK = (0, 0, 0)
GREEN = (0, 128, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)


def draw_window():

    # Set display background
    WIN.fill(BLACK)

    # Draw shapes
    pygame.draw.circle(surface=WIN, center=(400, 300), radius=20, color=GREEN)
    pygame.draw.polygon(surface=WIN, points=((410, 270), (460, 320), (390, 290)), color=RED)
    pygame.draw.circle(surface=WIN, center=(200, 150), radius=30, color=YELLOW)
    pygame.draw.polygon(surface=WIN, points=((180, 190), (200, 140), (190, 270)), color=BLUE)

    # Update display
    pygame.display.update()


def main():

    clock = pygame.time.Clock()
    run = True
    count_colours = True
    while run:
        clock.tick(FPS)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        draw_window()

        while count_colours:  # Run once only
            data = pygame.surfarray.pixels2d(WIN)
            unique, counts = np.unique(data, return_counts=True)
            print(dict(zip(unique, counts)))
            count_colours = False


if __name__ == "__main__":
    main()

Output:

{0: 474303, 255: 1256, 32768: 867, 16711680: 1061, 16776960: 2513}

enter image description here

Alan
  • 509
  • 4
  • 15
  • 1
    Surely you could just create a surface for each object, draw it on there, use the surfarray on the surface but not blit that surface to the screen until you are ready? – marienbad May 31 '21 at 13:51
  • @marienbad You're right, my problem is solved by creating multiple Surfaces, only one of which is displayed to the user. I'm new to Pygame and got confused when I read the documentation on pygame.display: *"Pygame has a single display Surface that is either contained in a window or runs full screen."* I though this meant that Pygame has a *single Surface* that must be displayed in a window or full screen. Clearly that would make no sense at all. Thanks for pointing me in the right direction. – Alan Jun 01 '21 at 09:56

0 Answers0