Pygame with Multiple Windows

Pygame with Multiple Windows

The short answer is no, creating two pygame windows in the same process is not possible (as of April 2015). If you want to run two windows with one process, you should look into pyglet or cocos2d.

An alternative, if you must use pygame, is to use inter-process communication. You can have two processes, each with a window. They will relay messages to each other using sockets. If you want to go this route, check out the socket tutorial here.

Multiple Displays in Pygame

Do you really need multiple windows? I mean, do you really need them?

If yes, then you should probably use pyglet/cocos2d instead.

To have multiple windows in pygame, you need multiple processes (one for each window). While this is doable, it's not worth the efford. You'll need IPC to exchange data between the windows, and I guess your code will become error-prone and ugly.

Go with pyglet when you need more than one window.

The better solution is probably to divide your game into scenes. Create multiple scenes so that each one represent one stage of the game, something like MenuScene, MainScene, BattleScene, GameOverScene, OptionScene etc.

Then let each of those scenes handle input/drawing of that very part of the game.

  • MenuScene handles drawing and input etc. of the game's menu
  • MainScene handles drawing and input etc. of the running game
  • BattleScene handles drawing and input etc. of whatever you do in run_ani

In your mainloop, just pass control over to the current scene by implementing the methods draw(), handle_event(), and update().

Some example code to get the idea:

scenes = {'Main': MainScene(),
'Battle': BattleScene()} #etc

scene = scenes['Main']

class MainScene():
...
def handle_event(self, event):
if event.type == KEYUP:
if event.key == K_a:
scene = scenes['Battle']
...

class BattleScene():
...
def draw(self):
# draw your animation

def update(self):
# if animation is over:
scene = scenes['Main']

...

def main_game():
ending=False
While Not ending:
clock.tick(30)
for event in pygame.event.get():
scene.handle_event(event)
scene.update()
scene.draw()

This is an easy way to cleanly seperate the game logic and allow context switching.

Why does multiprocessing open up multiple pygame windows despite not processing anything pygame related?

I believe this encounters the same problem as you, and there is a solution there:

Python Multiprocessing: Execute code serially before and after parallel execution

Basically you have to move screen = pygame.display.set_mode([800, 400]) into __main__ so that it only got executed once.

Hope this somewhat helps!

Multiple Displays in Pygame

Do you really need multiple windows? I mean, do you really need them?

If yes, then you should probably use pyglet/cocos2d instead.

To have multiple windows in pygame, you need multiple processes (one for each window). While this is doable, it's not worth the efford. You'll need IPC to exchange data between the windows, and I guess your code will become error-prone and ugly.

Go with pyglet when you need more than one window.

The better solution is probably to divide your game into scenes. Create multiple scenes so that each one represent one stage of the game, something like MenuScene, MainScene, BattleScene, GameOverScene, OptionScene etc.

Then let each of those scenes handle input/drawing of that very part of the game.

  • MenuScene handles drawing and input etc. of the game's menu
  • MainScene handles drawing and input etc. of the running game
  • BattleScene handles drawing and input etc. of whatever you do in run_ani

In your mainloop, just pass control over to the current scene by implementing the methods draw(), handle_event(), and update().

Some example code to get the idea:

scenes = {'Main': MainScene(),
'Battle': BattleScene()} #etc

scene = scenes['Main']

class MainScene():
...
def handle_event(self, event):
if event.type == KEYUP:
if event.key == K_a:
scene = scenes['Battle']
...

class BattleScene():
...
def draw(self):
# draw your animation

def update(self):
# if animation is over:
scene = scenes['Main']

...

def main_game():
ending=False
While Not ending:
clock.tick(30)
for event in pygame.event.get():
scene.handle_event(event)
scene.update()
scene.draw()

This is an easy way to cleanly seperate the game logic and allow context switching.

Creating two pygame screens using multiprocessing

You're duplicating the process after pygame.init() is called. So probably they're sharing window handles, etc.

If the process is copied before the init(), it works OK.

import multiprocessing
import pygame
import os

def handleUpdates( window, colour ):
""" Simple pygame message loop.
Paints the window in a single colour,
handles quit event """
clock = pygame.time.Clock()
exiting = False

while not exiting:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
exiting = True

# draw the window
window.fill( colour )
pygame.display.flip()

# save CPU
clock.tick( 30 )

pygame.quit()

def pyGameWindow( name, window_pos, colour ):
""" Initialise PyGame for a new window """
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % window_pos
pygame.init()
window = pygame.display.set_mode( ( 300, 300 ) )
pygame.display.set_caption( name )
handleUpdates( window, colour )

if __name__ == '__main__':
p1 = multiprocessing.Process(target=pyGameWindow, args=('Window One', ( 100, 100 ), (255, 0, 0 )))
p1.start()
p2 = multiprocessing.Process(target=pyGameWindow, args=('Window Two', ( 500, 100 ), (255, 255, 0 )))
p2.start()

p1.join()
p2.join()

Create/manage two displays in the same window in Pygames

Sounds like the easiest thing would be to just create two separate surfaces and treat them as separate screens. For example, if you have a 800 x 600 window, you could create a 600 x 600 image and a 200 x 600 image.

Something like this...

...

actual_screen = pygame.display.set_mode((800, 600))
simulation_screen = pygame.Surface((600, 600))
interface_screen = pygame.Surface((200, 600))

...

while running:

# ... game code that renders to each surface as though
# they are separate screens ...

actual_screen.blit(simulation_screen, (0, 0))
actual_screen.blit(interface_screen, (600, 0))
pygame.display.flip()

...

Open pygame fullscreen window in secondary monitor

I found the answer to my problem by using SDL environment variables before initializing pygame:

x = 0
y = 0
os.environ['SDL_VIDEO_WINDOW_POS'] = f"{x},{y}"

By specifying x, the left border of the window will open in that location.

e.g. If you have two monitors with resolution 1920*1080 and x=0, the window will open in the left monitor; if x=1920 it will opened in the right monitor.

Since I also want the window to be fullcreen without a border I specify the flag NOFRAME in set_mode:

screen = pygame.display.set_mode((screen_width, screen_height), flags = pygame.NOFRAME)


Related Topics



Leave a reply



Submit