why does the while loop keep making the game crash in pygame?

前端 未结 2 1826
既然无缘
既然无缘 2020-12-21 14:43

the code works just fine until I add the while true: also for some reason, the sleep function makes the entire code wait. however, I want only the parts after sleep() to wai

相关标签:
2条回答
  • 2020-12-21 15:36

    You can see that in your program, no call is being made to the event queue. In the pygame documentation for pygame.event.pump(), it says

    "If you fail to make a call to the event queue for too long, the system may decide your program has locked up."

    This causes the program to seem to be unresponsive. To solve this call the function pygame.event.pump() after pygame.init() so that the events are internally handeled

    import pygame, sys
    pygame.init()
    pygame.event.pump()
    from time import sleep
    
    screen = pygame.display.set_mode((500,400))
    PINK = (255,192,203)
    WHITE = (255,255,255)
    screen.fill(PINK)
    pygame.display.update()
    
    
    font = pygame.font.SysFont("comicsansms", 72)
    text = font.render("loading", True, WHITE)
    textrect = text.get_rect()
    textrect.center = (225,40)
    screen.blit(text,textrect)
    
    
    while True:
        sleep(1)
        text = font.render(".", True, WHITE)
        textrect = text.get_rect()
        textrect.center = (350,40)
        screen.blit(text,textrect)
        sleep(0.5)
        text = font.render(".", True, WHITE)
        textrect = text.get_rect()
        textrect.center = (370,40)
        screen.blit(text,textrect)
        sleep(0.5)
        text = font.render(".", True, WHITE)
        textrect = text.get_rect()
        textrect.center = (390,40)
        screen.blit(text,textrect)
        sleep(0.5)
    
    0 讨论(0)
  • 2020-12-21 15:43

    [...] The sleep function makes the entire code wait

    Yes! It does. The entire thread anyway. PyGame uses an "event model" to work with the user-interface. Your code above "fights" against this, but while you might see the updates on-screen, essentially the application has "locked up" (is non-responsive) as far as your operating environment it concerned. Your OS thinks this because your program is not accepting events.

    A PyGame application should process the events in the event-queue (even if it does nothing except exit). So instead of implementing times with time.sleep(), it's much better to use the real-time clock provided by pygame.time.get_ticks(). This function returns the time as the number of milliseconds since your program started. Your program needs multiple things to happen at certain times. These can be created at the beginning (time=0), with a time in the future. If the clock says this time has passed, then do the things.

    One way to implement this is to create a simple structure to hold your text items, and the time they need to be drawn in the future:

    ### Structure to hold some text to draw
    ### after a certain number of seconds have passed
    class TimedText:
        def __init__( self, text, position, at, colour=WHITE ):
            self.text     = text
            self.position = position,
            self.at_time  = at * 1000    # convert to milliseconds
            self.colour   = colour
    

    Create these items before your main loop starts:

    ### Make some timed-text structures/objects
    timed_texts = []
    timed_texts.append( TimedText( "loading", (225,40), 0.0 ) )
    timed_texts.append( TimedText( ".",       (350,40), 0.5 ) )
    timed_texts.append( TimedText( ".",       (370,40), 1.0 ) )
    timed_texts.append( TimedText( ".",       (390,40), 1.5 ) )
    

    Then in your main loop, look through each of the items, drawing the texts that need to be draw - but according to the clock.

    # Loop through each timed-text structure
    #     Check if enough time has elapsed, and if-so, draw the text:
    for tt in timed_texts:
        if ( time_now >= tt.at_time ):   # has enough time elapsed
            text = font.render( tt.text, True, tt.colour )
            textrect = text.get_rect()
            textrect.center = tt.position
            screen.blit( text, textrect )
    

    This allows your code to process the events, and still have timed text-animation.

    Reference code:

    import pygame
    
    # Window size
    WINDOW_WIDTH    = 500
    WINDOW_HEIGHT   = 400
    WINDOW_SURFACE  = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
    
    PINK  = (255,192,203)
    WHITE = (255,255,255)
    
    ### initialisation
    pygame.init()
    pygame.mixer.init()
    screen = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
    pygame.display.set_caption("Going Dotty...")
    
    
    ### Structure to hold some text to draw
    ### after a certain number of seconds have passed
    class TimedText:
        def __init__( self, text, position, at, colour=WHITE ):
            self.text     = text
            self.position = position,
            self.at_time  = at * 1000    # convert to milliseconds
            self.colour   = colour
    
    
    ### Make some timed-text structures/objects
    font = pygame.font.SysFont("comicsansms", 72)
    timed_texts = []
    timed_texts.append( TimedText( "loading", (225,40), 0 ) )
    timed_texts.append( TimedText( ".",       (350,40), 0.5 ) )
    timed_texts.append( TimedText( ".",       (370,40), 1.0 ) )
    timed_texts.append( TimedText( ".",       (390,40), 1.5 ) )
    
    ### Main Loop
    clock = pygame.time.Clock()
    done = False
    while not done:
    
        # Handle user-input
        for event in pygame.event.get():
            if ( event.type == pygame.QUIT ):
                done = True
            elif ( event.type == pygame.MOUSEBUTTONUP ):
                # On mouse-click
                pass
            elif ( event.type == pygame.KEYUP ):
                # On key-release
                #keys = pygame.key.get_pressed()
                pass
    
        # Update the window, but not more than 60fps
        screen.fill( PINK )
    
        time_now = pygame.time.get_ticks()
    
        # Loop through each timed-text structure
        #     Check if enough time has elapsed, and if-so, draw the text:
        for tt in timed_texts:
            if ( time_now >= tt.at_time ):   # has enough time elapsed
                text = font.render( tt.text, True, tt.colour )
                textrect = text.get_rect()
                textrect.center = tt.position
                screen.blit( text, textrect )
    
        pygame.display.flip()
        clock.tick_busy_loop(60)
    
    
    pygame.quit()
    
    0 讨论(0)
提交回复
热议问题