Pygame 多个 Windows
Pygame with Multiple Windows
我需要构建一个包含多个 windows 的应用程序。在其中一个 windows 中,我需要能够玩一个简单的游戏,另一个 window 必须显示问题并获得影响游戏的用户的响应。
(1) 我想使用 pygame 来制作游戏。有没有简单的方法让pygame与多个windows一起操作?
(2) 如果没有简单的方法来解决 (1),是否有一种简单的方法可以使用其他一些 python GUI 结构,让我 运行 pygame 和另一个 window 同时?
简短的回答是否定的,在同一进程中创建两个 pygame windows 是不可能的(截至 2015 年 4 月)。如果你想 运行 两个 windows 用一个过程,你应该看看 pyglet or cocos2d.
如果必须使用 pygame,另一种方法是使用进程间通信。您可以有两个进程,每个进程都有一个 window。他们将使用套接字相互中继消息。如果您想走这条路,请查看套接字教程 here。
在内部set_mode() 可能会设置一个指针,代表唯一显示器的内存。所以如果我们写:
screenA = pygame.display.set_mode((500,480), 0, 32)
screenB = pygame.display.set_mode((500,480), 0, 32)
例如我们稍后可以做类似的事情:
screenA.blit(background, (0,0))
screenB.blit(player, (100,100))
两次 blit() 调用都将在同一表面上进行 blit。 screenA 和 screenB 指向相同的内存地址。使用 2 windows 在 pygame.
中很难实现
是的,这是可能的。 SDL2能够打开多个windows。在示例文件夹中,您可以查看“video.py”。
https://github.com/pygame/pygame/blob/main/examples/video.py
"此示例需要 pygame 2 和 SDL2。_sdl2 是实验性的,将会更改。"
几天来我一直在努力做到这一点,我终于取得了进展。这算不算简单?或者甚至是“在”pygame。在这个例子中,我什至从来没有调用 pygame.init() 这似乎妨碍了。事件泵是 运行(用于鼠标和键盘),但并非所有正常事件似乎都通过(特别是 FOCUSGAINED 和 LOST)。在这个例子中,每个 window 将它的状态(大小、位置等)呈现给它自己。我还有将 SDL windows 与 pygame 显示混合使用的版本。但是那些涉及封装 Window 而不是扩展它。
为了在这些 windows 上绘制,您可以像往常一样在原版表面上绘制,然后使用与 window 相关联的渲染器创建将更新 window. (texture.draw(), renderer.present)。您不使用 display.update() 或 flip() 因为您没有使用 pygame 显示表面。
X11 包只是我的实验性 windowing 东西,与 X11 无关。我认为我所有的导入都是明确的,所以应该很容易找出缺失的部分。
from typing import List
from pygame import Rect, Surface, Color
import pygame.event
from pygame.event import Event
from pygame.freetype import Font
from pygame._sdl2.video import Window, Renderer, Texture
from X11.windows import DEFAULT_PAD, default_font, window_info
from X11.text import prt
class MyWindow(Window):
def __init__(self, font: Font=None):
super().__init__()
self._font = font if font else default_font()
self.resizable = True
self._renderer = None
def destroy(self) -> None:
super().destroy()
def update(self):
r = self.renderer
r.draw_color = Color('grey')
r.clear()
#self.render_line(f"TICKS: {pg.time.get_ticks()}", 5, size=16.0)
txt: List[str] = window_info(self)
self.render_text(txt, lineno=0)
r.present()
@property
def renderer(self):
if self._renderer is None:
try:
self._renderer = Renderer.from_window(self)
except:
self._renderer = Renderer(self)
return self._renderer
def render_text(self, txt: List[str], lineno: int=0):
for line in txt:
self.render_line(line, lineno, size=16.0)
lineno += 1
def render_line(self, txt: str, lineno: int = 0, size: float = 0.0):
font = self._font
line_spacing = font.get_sized_height(size) + DEFAULT_PAD
x = DEFAULT_PAD
y = DEFAULT_PAD + lineno * line_spacing
# compute the size of the message
src_rect = font.get_rect(txt, size=size)
# create a new surface (image) of text
l_surf = Surface((src_rect.width, src_rect.height))
src_rect = font.render_to(l_surf, (0, 0), txt, size=size)
# get ready to draw
texture = Texture.from_surface(self.renderer, l_surf)
dst = Rect(x, y, src_rect.width, src_rect.height)
texture.draw(None, dst)
_running: bool = False
def test():
global _running
win1 = MyWindow()
win2 = MyWindow()
my_windows = {win1.id: win1, win2.id: win2}
win = win1
rnd = win1.renderer
print("pygame.get_init():", pygame.get_init())
print("pygame.display.get_init():", pygame.display.get_init())
print("pygame.mouse.get_pos():", pygame.mouse.get_pos())
clock = pygame.time.Clock()
_running = True
while _running:
events = pygame.event.get()
for event in events:
if event.type != pygame.MOUSEMOTION:
print(event)
if event.type == pygame.QUIT:
_running = False
elif event.type == pygame.WINDOWENTER:
win = my_windows[event.window.id]
print(f"Enter Window ({event.window.id}")
elif event.type == pygame.WINDOWLEAVE:
pass
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
_running = False
if event.key == pygame.K_1:
win = my_windows[1]
rnd = win.renderer
if event.key == pygame.K_2:
win = my_windows[2]
rnd = win.renderer
elif event.key == pygame.K_b:
rnd.draw_color = Color('blue')
rnd.clear()
elif event.key == pygame.K_g:
rnd.draw_color = Color('grey')
rnd.clear()
elif event.key == pygame.K_t:
win.render_line("Hello, world")
elif event.key == pygame.K_s:
surface = pygame.display.get_surface()
print("surface: ", surface)
elif event.key == pygame.K_f:
pygame.display.flip()
# pygame.error: Display mode not set
elif event.key == pygame.K_u:
pygame.display.update()
# pygame.error: Display mode not set
for win in my_windows.values():
win.update()
clock.tick(40)
if __name__ == '__main__':
test()
我需要构建一个包含多个 windows 的应用程序。在其中一个 windows 中,我需要能够玩一个简单的游戏,另一个 window 必须显示问题并获得影响游戏的用户的响应。
(1) 我想使用 pygame 来制作游戏。有没有简单的方法让pygame与多个windows一起操作?
(2) 如果没有简单的方法来解决 (1),是否有一种简单的方法可以使用其他一些 python GUI 结构,让我 运行 pygame 和另一个 window 同时?
简短的回答是否定的,在同一进程中创建两个 pygame windows 是不可能的(截至 2015 年 4 月)。如果你想 运行 两个 windows 用一个过程,你应该看看 pyglet or cocos2d.
如果必须使用 pygame,另一种方法是使用进程间通信。您可以有两个进程,每个进程都有一个 window。他们将使用套接字相互中继消息。如果您想走这条路,请查看套接字教程 here。
在内部set_mode() 可能会设置一个指针,代表唯一显示器的内存。所以如果我们写:
screenA = pygame.display.set_mode((500,480), 0, 32)
screenB = pygame.display.set_mode((500,480), 0, 32)
例如我们稍后可以做类似的事情:
screenA.blit(background, (0,0))
screenB.blit(player, (100,100))
两次 blit() 调用都将在同一表面上进行 blit。 screenA 和 screenB 指向相同的内存地址。使用 2 windows 在 pygame.
中很难实现是的,这是可能的。 SDL2能够打开多个windows。在示例文件夹中,您可以查看“video.py”。
https://github.com/pygame/pygame/blob/main/examples/video.py
"此示例需要 pygame 2 和 SDL2。_sdl2 是实验性的,将会更改。"
几天来我一直在努力做到这一点,我终于取得了进展。这算不算简单?或者甚至是“在”pygame。在这个例子中,我什至从来没有调用 pygame.init() 这似乎妨碍了。事件泵是 运行(用于鼠标和键盘),但并非所有正常事件似乎都通过(特别是 FOCUSGAINED 和 LOST)。在这个例子中,每个 window 将它的状态(大小、位置等)呈现给它自己。我还有将 SDL windows 与 pygame 显示混合使用的版本。但是那些涉及封装 Window 而不是扩展它。
为了在这些 windows 上绘制,您可以像往常一样在原版表面上绘制,然后使用与 window 相关联的渲染器创建将更新 window. (texture.draw(), renderer.present)。您不使用 display.update() 或 flip() 因为您没有使用 pygame 显示表面。
X11 包只是我的实验性 windowing 东西,与 X11 无关。我认为我所有的导入都是明确的,所以应该很容易找出缺失的部分。
from typing import List
from pygame import Rect, Surface, Color
import pygame.event
from pygame.event import Event
from pygame.freetype import Font
from pygame._sdl2.video import Window, Renderer, Texture
from X11.windows import DEFAULT_PAD, default_font, window_info
from X11.text import prt
class MyWindow(Window):
def __init__(self, font: Font=None):
super().__init__()
self._font = font if font else default_font()
self.resizable = True
self._renderer = None
def destroy(self) -> None:
super().destroy()
def update(self):
r = self.renderer
r.draw_color = Color('grey')
r.clear()
#self.render_line(f"TICKS: {pg.time.get_ticks()}", 5, size=16.0)
txt: List[str] = window_info(self)
self.render_text(txt, lineno=0)
r.present()
@property
def renderer(self):
if self._renderer is None:
try:
self._renderer = Renderer.from_window(self)
except:
self._renderer = Renderer(self)
return self._renderer
def render_text(self, txt: List[str], lineno: int=0):
for line in txt:
self.render_line(line, lineno, size=16.0)
lineno += 1
def render_line(self, txt: str, lineno: int = 0, size: float = 0.0):
font = self._font
line_spacing = font.get_sized_height(size) + DEFAULT_PAD
x = DEFAULT_PAD
y = DEFAULT_PAD + lineno * line_spacing
# compute the size of the message
src_rect = font.get_rect(txt, size=size)
# create a new surface (image) of text
l_surf = Surface((src_rect.width, src_rect.height))
src_rect = font.render_to(l_surf, (0, 0), txt, size=size)
# get ready to draw
texture = Texture.from_surface(self.renderer, l_surf)
dst = Rect(x, y, src_rect.width, src_rect.height)
texture.draw(None, dst)
_running: bool = False
def test():
global _running
win1 = MyWindow()
win2 = MyWindow()
my_windows = {win1.id: win1, win2.id: win2}
win = win1
rnd = win1.renderer
print("pygame.get_init():", pygame.get_init())
print("pygame.display.get_init():", pygame.display.get_init())
print("pygame.mouse.get_pos():", pygame.mouse.get_pos())
clock = pygame.time.Clock()
_running = True
while _running:
events = pygame.event.get()
for event in events:
if event.type != pygame.MOUSEMOTION:
print(event)
if event.type == pygame.QUIT:
_running = False
elif event.type == pygame.WINDOWENTER:
win = my_windows[event.window.id]
print(f"Enter Window ({event.window.id}")
elif event.type == pygame.WINDOWLEAVE:
pass
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
_running = False
if event.key == pygame.K_1:
win = my_windows[1]
rnd = win.renderer
if event.key == pygame.K_2:
win = my_windows[2]
rnd = win.renderer
elif event.key == pygame.K_b:
rnd.draw_color = Color('blue')
rnd.clear()
elif event.key == pygame.K_g:
rnd.draw_color = Color('grey')
rnd.clear()
elif event.key == pygame.K_t:
win.render_line("Hello, world")
elif event.key == pygame.K_s:
surface = pygame.display.get_surface()
print("surface: ", surface)
elif event.key == pygame.K_f:
pygame.display.flip()
# pygame.error: Display mode not set
elif event.key == pygame.K_u:
pygame.display.update()
# pygame.error: Display mode not set
for win in my_windows.values():
win.update()
clock.tick(40)
if __name__ == '__main__':
test()