【问题标题】:How to end a loop, from outside the loop in python如何从python中的循环外部结束循环
【发布时间】:2020-05-25 13:13:49
【问题描述】:

我正在使用 python 3.8.3 制作一个 pygame 游戏, 在我的游戏中,我有一个开始屏幕,在这个 while 循环中:

def game_intro(): 
    intro = True 
    mixer.music.load("musicIntro.mp3")
    mixer.music.set_volume(0.02) 
    mixer.music.play(-1) 
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: 
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    intro = False
        screen.blit(startscherm_img, bordrect) 
        clock.tick(30)
        button("Start",302,517,94,44,donkerOranje,lichtOranje,"start")
        button("Music",553,517,94,44,donkerOranje,lichtOranje,"toggleMusic")
        button("Quit",803,517,94,44,donkerOranje,lichtOranje,"quit")
        pygame.display.flip() 
game_intro()

我正在调用我在上面定义的按钮功能:

def button(msg,x,y,w,h,ic,ac,action=None): 
    mousePos = pygame.mouse.get_pos() 
    click = pygame.mouse.get_pressed() 
    if x+w > mousePos[0] > x and y+h > mousePos[1] > y: 
        pygame.draw.rect(screen, ac, (x,y,w,h)) 
        if click[0] == 1 and action != None: 
            if action == "toggleMusic": 
                PAUSE.toggle()
                time.sleep(0.3)
            elif action == "quit": 
                pygame.quit()
                time.sleep(0.3)
            elif action == "start": 
                time.sleep(0.3)
                intro = False
    else:
        pygame.draw.rect(screen, ic, (x,y,w,h)) 

    smallText = pygame.font.SysFont("Bauhaus 93",30)
    textSurf, textRect = text_objecten(msg, smallText)
    textRect.center = ( (x+(w/2)), (y+(h/2)) )
    screen.blit(textSurf, textRect)

它基本上只是检查鼠标在某个区域内的点击,以及是否检测到它执行代码。

现在在我的开始屏幕上我有一个开始按钮,我希望它结束​​ game_intro() 循环,但是尝试intro = False 不会产生任何结果。 尝试break 不起作用,因为它必须在循环本身中。

所以我的问题是:如何让这个开始按钮真正结束 game_intro() 循环?

P.S 我对 Python 很陌生

【问题讨论】:

  • 如果你把它变成一个类,那么你可以将 intro 定义为一个字段并在方法中读取/更新它。

标签: python loops pygame


【解决方案1】:

据我所知,您在函数button 中设置了intro = False,但在game_intro 函数中还有一个名为intro 的变量。尽管它们具有相同的名称,但 Python 将它们视为不同的变量。

为了使intro 变量从一个函数到另一个函数的更改生效,您需要将intro 变量设置为全局变量,或者将intro 变量作为参数在两者之间传递功能。

选项 1:

intro = True

def button(msg,x,y,w,h,ic,ac,action=None): 
    global intro
    mousePos = pygame.mouse.get_pos() 
    click = pygame.mouse.get_pressed() 
    if x+w > mousePos[0] > x and y+h > mousePos[1] > y: 
        pygame.draw.rect(screen, ac, (x,y,w,h)) 
        if click[0] == 1 and action != None: 
            if action == "toggleMusic": 
                PAUSE.toggle()
                time.sleep(0.3)
            elif action == "quit": 
                pygame.quit()
                time.sleep(0.3)
            elif action == "start": 
                time.sleep(0.3)
                intro = False

def game_intro(): 
    global intro
    mixer.music.load("musicIntro.mp3")
    mixer.music.set_volume(0.02) 
    mixer.music.play(-1) 
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: 
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    intro = False
        screen.blit(startscherm_img, bordrect) 
        clock.tick(30)
        button("Start",302,517,94,44,donkerOranje,lichtOranje,"start")
        button("Music",553,517,94,44,donkerOranje,lichtOranje,"toggleMusic")
        button("Quit",803,517,94,44,donkerOranje,lichtOranje,"quit")
        pygame.display.flip() 
game_intro()

选项 2:

def button(msg,x,y,w,h,ic,ac, intro, action=None): 
    mousePos = pygame.mouse.get_pos() 
    click = pygame.mouse.get_pressed() 
    if x+w > mousePos[0] > x and y+h > mousePos[1] > y: 
        pygame.draw.rect(screen, ac, (x,y,w,h)) 
        if click[0] == 1 and action != None: 
            if action == "toggleMusic": 
                PAUSE.toggle()
                time.sleep(0.3)
            elif action == "quit": 
                pygame.quit()
                time.sleep(0.3)
            elif action == "start": 
                time.sleep(0.3)
                intro = False
    return intro

def game_intro(): 
    intro = True
    mixer.music.load("musicIntro.mp3")
    mixer.music.set_volume(0.02) 
    mixer.music.play(-1) 
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: 
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    intro = False
        screen.blit(startscherm_img, bordrect) 
        clock.tick(30)
        intro = button("Start",302,517,94,44,donkerOranje,lichtOranje,intro,"start")
        intro = button("Music",553,517,94,44,donkerOranje,lichtOranje,intro,"toggleMusic")
        intro = button("Quit",803,517,94,44,donkerOranje,lichtOranje,intro,"quit")
            pygame.display.flip() 
game_intro()

【讨论】:

  • 我尝试了您的两种解决方案,但都出现错误:UnboundLocalError: local variable 'intro' referenced before assignment
  • 你说得对,选项 2 中缺少 intro 定义。请使用选项 2 再试一次,我编辑了它,现在应该可以了。
【解决方案2】:

你可以做一些 OOP。尝试在这样的类中创建它:

class Intro:

  def __init__(self):
    self.intro = True

  def game_intro(self): 
    mixer.music.load("musicIntro.mp3")
    mixer.music.set_volume(0.02) 
    mixer.music.play(-1) 
    while self.intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: 
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    self.intro = False
        screen.blit(startscherm_img, bordrect) 
        clock.tick(30)
        button("Start",302,517,94,44,donkerOranje,lichtOranje,"start")
        button("Music",553,517,94,44,donkerOranje,lichtOranje,"toggleMusic")
        button("Quit",803,517,94,44,donkerOranje,lichtOranje,"quit")
        pygame.display.flip() 

  def button(self, msg,x,y,w,h,ic,ac,action=None): 
    mousePos = pygame.mouse.get_pos() 
    click = pygame.mouse.get_pressed() 
    if x+w > mousePos[0] > x and y+h > mousePos[1] > y: 
        pygame.draw.rect(screen, ac, (x,y,w,h)) 
        if click[0] == 1 and action != None: 
            if action == "toggleMusic": 
                PAUSE.toggle()
                time.sleep(0.3)
            elif action == "quit": 
                pygame.quit()
                time.sleep(0.3)
            elif action == "start": 
                time.sleep(0.3)
                self.intro = False


obj = Intro()
start = obj.gameintro()

intro 是在使用 self 的实例中定义的,因此可以在类中的任何位置调用它。

【讨论】:

    【解决方案3】:

    虽然我有一段时间没有做过 python,但你可以尝试将你的循环作为一个新线程运行,然后在作为一个线程手动完成后将其杀死,老实说,将 intro 设置为 false 应该可以工作我会先做一些调试以实际检查 intro 是否设置为 false。尽管在进一步阅读您的代码后,我注意到您实际上调用了函数 game_intro() 两次,这会导致您循环,因为变量 intro 是在函数的一侧定义的,因此调用函数 game_intro() 会重置循环,因此可能会删除最后调用,因为你已经在一个while循环中拥有它。另一种选择是在函数欢呼之外定义变量 intro

    【讨论】:

      【解决方案4】:

      线程事件

      将全局范围变量(在两个函数之外)分配为threading.Event 实例。

      然后,在您想要控制循环时设置并清除该事件。

      import threading
      
      
      do_intro_loop = threading.Event
      
      
      def button(action=None):
        if action == "start":
          do_intro_loop.clear()
      
      def into():
        do_intro_loop.set()
        while do_intro_loop.is_set():
          # show do intro stuff here
          pass
      
      intro()
      

      【讨论】:

        猜你喜欢
        • 2015-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多