Pygame中的多个显示器

12

我正在制作一个小游戏,想要从主窗口中单独开启另一个窗口。

我将主要的游戏内容放在主窗口中,并希望在用户执行某些操作时打开一个新窗口并进行一些动画。

在下面的示例代码中,当用户按下“a”时,我希望它可以打开一个新窗口并在其中进行 blit 操作。

这里我设置了两个窗口:(我知道这不起作用,我正在询问如何实现)

SCREEN_X = 400
SCREEN_Y = 400
BSCREEN_X = 240
BSCREEN_Y = 160

BATTLE_SCENE = pygame.display.set_mode((BSCREEN_X, BSCREEN_Y))
SCREEN = pygame.display.set_mode((SCREEN_X, SCREEN_Y))

然后程序:

def run_ani ():
    #Do animation, blitting to BATTLE_SCENE
    return

def main_game():
    ending=False
    while ending==False:
        clock.tick(30)
        for event in pygame.event.get():
            if event.type == pygame.QUIT: ending=True
            if event.type == KEYDOWN: # key down or up?
                if event.key == K_ESCAPE:
                    ending=True # Time to leave
                    print("Stopped Early by user")
                elif event.key == K_a:
                    run_ani()
        #Normal screen motion, blitting to SCREEN
        if ending: pygame.quit()
    return
到目前为止,这段代码的作用是绘制主屏幕,然后当按下 A 键时,它停止了绘制主屏幕动画,但仍绘制主屏幕上的其他动画并在左上角绘制。
我相当确定之所以会这样,是因为我将“BATTLE_SCENE”设置为小于主屏幕,因此在将图像绘制到“BATTLE_SCENE”时,它会在我创建的区域(240x160)顶部角落进行绘制。
然而,我希望“BATTLE_SCENE”成为一个单独的窗口,这样当我按下 "a" 键时,它将弹出,在其上执行操作,然后关闭或至少移到主屏幕后面。
如何做到这一点?这是否可能?

1
那是不是意味着有一种我应该这样做的方式?更详细的解释会更好 :) - hammythepig
在现有窗口中为动画制作一个区域。 - Oleh Prypin
那么基本上,我已经有了什么?你知道没有比这更深入的了吗? - hammythepig
3个回答

12

你真的需要多个窗口吗?我的意思是,你确实需要它们吗?

如果是的话,你应该考虑使用 pyglet/cocos2d 替代pygame。

在pygame中要有多个窗口,就需要多个进程(每个窗口一个进程)。虽然这是可行的,但值得花费的努力并不值得。您需要IPC来交换窗口之间的数据,我猜您的代码将变得容易出错且难看。

当您需要多个窗口时,请使用pyglet。

更好的解决方案可能是将游戏分成场景。创建多个场景,以便每个场景代表游戏的一个阶段,例如MenuScene、MainScene、BattleScene、GameOverScene、OptionScene等。

然后让每个场景处理该部分游戏的输入/绘图等操作。

  • MenuScene处理游戏菜单的绘制和输入等操作
  • MainScene处理运行中的游戏的绘制和输入等操作
  • BattleScene处理在run_ani中进行的所有绘制和输入等操作

在主循环中,只需通过实现draw()handle_event()update()方法将控制权传递给当前场景。

以下是一些示例代码,用于了解基本思路:

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()

这是一种简单的方法,可以清晰地分离游戏逻辑并允许上下文切换。


哦,我明白了,使用一些类。我从来不喜欢类,因为它们看起来很混乱,但我理解你在那里写的东西。我想我甚至会更深入地研究类并学到更多东西。现在我接受了你的答案,这似乎是实现我想要的简单有效的方法,非常感谢! :) - hammythepig
这是一个聪明的想法,分享你对这些事情的知识。我喜欢学习所有这些东西,它既有趣又有意思。 - hammythepig

3

======================================编辑=========================================

实际上这不起作用。显然pygame只支持一个显示屏,当您初始化另一个时,它将关闭第一个。您将保留两个变量,实际上是同一个表面。相反,您可以增加窗口大小并在其侧播放战斗场景,为此,您可以再次使用不同的值调用pygame.display.set_mode()。引用显示屏的变量仍然可用,因为它将其引用更改为新引用。场景结束后,您可以通过相同的方式减少窗口大小。

==================================================================================

基本上发生的事情是你运行一个循环,每次迭代都会呈现和显示一个新的帧。 当你在循环内部调用一个函数时,它不会继续运行直到你完成运行该函数。
解决这个问题的一种方法是只需在主循环中不断地调用更新战斗场景的函数。 另一种方法是使用线程。线程基本上是在同一时间运行多个脚本("线程")。
幸运的是,Python已经为我们实现了线程模块。 这里太长了,我无法在这里解释模块,但你可以在这里学习它here。如果你以前没有使用过线程,它可能有点复杂,但一段时间后会变得更容易。 如果你想了解更多关于线程的知识,你可以去这里here
具体来说,在这里,你可以拥有两个线程,一个用于每个循环/窗口,并在同一时间运行它们。
希望我能帮到你!

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接