Time Delay and keeping track of the of # of click

生来就可爱ヽ(ⅴ<●) 提交于 2021-01-28 05:13:22

问题


I' am trying to make a program using pygame. The program involves two tiles that switch colours and turn back into their original color once the two tiles have been clicked and after a 1-second delay. My problem is that whenever I tried to implement the pygame.time.delay , it delays the whole system and also affects the scoring mechanism of the program. I tried solving this problem by writing the codes found in handle_color_change and update methods in the game class

Any suggestions to fix this problem is greatly appreciated

    import pygame,time,random
    # User-defined functions

def main():
    # for initializing all pygame modules
    pygame.init()
    # this creates the pygame display window 
    surface_width = 500
    surface_height = 400
    surface = pygame.display.set_mode((surface_width,surface_height))
    # this sets the caption of the window to 'Pong'
    pygame.display.set_caption('Painting')
    
    # creates a game object
    game = Game(surface, surface_width, surface_height)
    # this starts the game loop by calling the play method found in the game object 
    game.play()
    # quits pygame and cleans up the pygame window
    pygame.quit()


# User-defined classes

class Game:
    # an object in this class represents the complete game
    
    def __init__(self,surface,surface_width,surface_height):
        #  # Initialize a Game.
        # - self is the Game to initialize
        # - surface is the display window surface object
        # - surface_width is the display width size
        # - surface_height is the display height size
        
        # attributes that are needed to run any game
        self.surface = surface 
        self.surface_width = surface_width
        self.surface_height = surface_height
        self.close_clicked = False
        self.surface_color = pygame.Color('black')
        
        # attributes that are needed to run this specific game
        self.FPS = 60
        self.game_clock = pygame.time.Clock()
        self._continue = True 
        self.score = [0,0]
        self.max_mismatch = 5 
        
        # Game specific objects
        self.default_color = 'white'
        self.color_options = ('blue' , 'red', 'yellow', 'green')
        self.tile_width = 50
        self.tile_height = 150
        self.tile_left = Tile( self.default_color, (self.surface_width/3) - self.tile_width, (self.surface_height/2)/ 2 , self.tile_width, self.tile_height , self.surface) 
        self.tile_right = Tile(self.default_color, self.surface_width/2 + self.tile_width, (self.surface_height/2)/ 2 
                               ,self.tile_width, self.tile_height , self.surface) 
        
        
        
    def play(self):
        # this is main game loop
        # plays the game until the players has closed the window or the score of a players equals the max score 
        # - self is the game that should be continued or not
        
        while not self.close_clicked:
            self.main_handle_events()
            self.draw()
            self.update()
            self.game_clock.tick(self.FPS)  
    
    
    def draw(self):
        # this draws the circle and the rectangles that are needed for this specific game
        # -self is the Game to draw
        
        self.surface.fill(self.surface_color)
        self.tile_left.draw()
        self.tile_right.draw()
        self.display_score_match()
        self.display_score_mismatch(self.surface_width)
        pygame.display.update() # makes the updated surface appear on the display
               
        
    
    def update(self):       
        events = pygame.event.get()    
        if self.handle_color_change(events):
            pygame.time.delay(1000)
            self.tile_left.set_color(self.default_color)    
            self.tile_right.set_color(self.default_color)
            self.update_score()
                              
        
    
    def main_handle_events(self):
        # handles each user events by changing the game state appropriately
        # -self is the Game of whose events are handled
        
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT:
                self.close_clicked = True
            if event.type == pygame.MOUSEBUTTONDOWN:
                self.handle_color_change(event)           
                #self.update_score()
        #self.handle_color_change(event)
    
    def display_score_match(self):
        text_string = 'Match: ' + str(self.score[0])
        text_colour = pygame.Color('white')
        text_font = pygame.font.SysFont('Times New Roman',25)
        text_image = text_font.render(text_string, True, text_colour)
        text_pos = [0,0]
        self.surface.blit(text_image, text_pos)
        
    def display_score_mismatch(self, surface_width):
        text_string = 'Mismatch: ' + str(self.score[1])
        text_colour = pygame.Color('white')
        text_font = pygame.font.SysFont('Times New Roman',25)
        text_image = text_font.render(text_string, True, text_colour)
        text_pos = [(surface_width - text_image.get_width()), 0]
        self.surface.blit(text_image, text_pos)    
    
 

    def handle_color_change(self, event):
        tile_clicked = 0 
        change_white = False        
        
        if event.button == 1 and self.tile_left.inside_tile(event.pos) == True:     
            self.tile_left.set_color(random.choice(self.color_options)) 
            tile_clicked += 1 
        
        if event.button == 1 and self.tile_right.inside_tile(event.pos) == True:    
            self.tile_right.set_color(random.choice(self.color_options))             
            tile_clicked  +=1 
        
        if tile_clicked == 2:
            change_white = True 
            tile_clicked = 0 
        
        return change_white
        
        
    def update_score(self):
        if self.tile_left.color_match(self.tile_right) == True:
            self.score[0] = self.score[0] + 1 
        else:
            self.score[1] = self.score[1] + 1 

         
class Tile:
    
    def __init__(self, rect_color, rect_left, rect_top, rect_width, rect_height,surface):
    # Initialize a rectabgle which is used as a paintbrush.
    # - self is the rectangle to initialize
    # - rect_color is the pygame.Color of the dot
    # - rect_height is the int length of the rectangle in the y axis
    # - rect_width is the int width of the rectangle in the x axis
    # - rect_left is the int coordinate position of the rectangle in the x axis
    # - rect_top is the int coordinate position of the rectangle in the y axis
    # - rect_velocity is a list of x and y components and the speed of which the rectangles can move           
    
        self.rect_colour = pygame.Color(rect_color)
        self.rect_height = rect_height
        self.rect_width = rect_width
        self.rect_left = rect_left
        self.rect_top = rect_top 
        self.surface = surface
        self.rect_parameters = pygame.Rect(rect_left, rect_top, rect_width, rect_height)        
    
    def draw(self):
        # draws the rectangle on the surface
        # - self is the rectangle
        
        pygame.draw.rect(self.surface, self.rect_colour, self.rect_parameters)
        
            
    def inside_tile(self, position):
        inside = False
        if self.rect_parameters.collidepoint(position):
            inside = True
        return inside
    
    def set_color(self, color):
        self.rect_colour = pygame.Color(color)
    
    def color_match(self, other_tile):
        match = False 
        if self.rect_colour == other_tile.rect_colour:
            match = True
        return match

main()

回答1:


Never use a delay in your application loop. Use the application loop. Compute the point in time when the rectangles have to change color back. Change the color after the current time is greater than the calculated point of time.
In pygame the system time can be obtained by calling pygame.time.get_ticks(), which returns the number of milliseconds since pygame.init() was called. See pygame.time module.

Add 2 attributes self.tile_clicked = 0 and self.turn_white_time = 0 to the class Game:

class Game:

    def __init__(self,surface,surface_width,surface_height):
        # [...]

        self.tile_clicked = []
        self.turn_white_time = 0

Compute the the point in time when the rectangles have to change color back after the 2nd rectangle was clicked:

class Game:
    # [...]

    def handle_color_change(self, event):
        
        if len(self.tile_clicked) < 2:         
        
            if 1 not in self.tile_clicked:
                if event.button == 1 and self.tile_left.inside_tile(event.pos) == True:     
                    self.tile_left.set_color(random.choice(self.color_options)) 
                    self.tile_clicked.append(1) 
            
            if 2 not in self.tile_clicked:
                if event.button == 1 and self.tile_right.inside_tile(event.pos) == True:    
                    self.tile_right.set_color(random.choice(self.color_options))             
                    self.tile_clicked.append(2) 
    
            if len(self.tile_clicked) == 2:
                delay_time = 1000 # 1000 milliseconds == 1 second
                self.turn_white_time = pygame.time.get_ticks() + delay_time    

get_ticks() returns the current time. A time is just a number. get_ticks() + delay_time is a time in the future. When the program is running, the current time is continuously retrieved and compared with turn_white_time. At some point the current time is greater than turn_white_time and the color of the rectangles is changed.

Change back to the white color after the current time is greater than the calculated point of time in update:

class Game:
    # [...]

    def update(self):       
        current_time  = pygame.time.get_ticks()
        if len(self.tile_clicked) == 2 and current_time > self.turn_white_time:
            self.tile_left.set_color(self.default_color)    
            self.tile_right.set_color(self.default_color)
            self.tile_clicked = []

Complete example:

import pygame,time,random
    # User-defined functions

def main():
    # for initializing all pygame modules
    pygame.init()
    # this creates the pygame display window 
    surface_width = 500
    surface_height = 400
    surface = pygame.display.set_mode((surface_width,surface_height))
    # this sets the caption of the window to 'Pong'
    pygame.display.set_caption('Painting')
    
    # creates a game object
    game = Game(surface, surface_width, surface_height)
    # this starts the game loop by calling the play method found in the game object 
    game.play()
    # quits pygame and cleans up the pygame window
    pygame.quit()


# User-defined classes

class Game:
    # an object in this class represents the complete game
    
    def __init__(self,surface,surface_width,surface_height):
        #  # Initialize a Game.
        # - self is the Game to initialize
        # - surface is the display window surface object
        # - surface_width is the display width size
        # - surface_height is the display height size
        
        # attributes that are needed to run any game
        self.surface = surface 
        self.surface_width = surface_width
        self.surface_height = surface_height
        self.close_clicked = False
        self.surface_color = pygame.Color('black')
        
        # attributes that are needed to run this specific game
        self.FPS = 60
        self.game_clock = pygame.time.Clock()
        self._continue = True 
        self.score = [0,0]
        self.max_mismatch = 5 
        
        # Game specific objects
        self.default_color = 'white'
        self.color_options = ('blue' , 'red', 'yellow', 'green')
        self.tile_width = 50
        self.tile_height = 150
        self.tile_left = Tile( self.default_color, (self.surface_width/3) - self.tile_width, (self.surface_height/2)/ 2 , self.tile_width, self.tile_height , self.surface) 
        self.tile_right = Tile(self.default_color, self.surface_width/2 + self.tile_width, (self.surface_height/2)/ 2 
                               ,self.tile_width, self.tile_height , self.surface) 

        self.tile_clicked = []
        self.turn_white_time = 0
        
        
        
    def play(self):
        # this is main game loop
        # plays the game until the players has closed the window or the score of a players equals the max score 
        # - self is the game that should be continued or not
        
        while not self.close_clicked:
            self.main_handle_events()
            self.draw()
            self.update()
            self.game_clock.tick(self.FPS)  
    
    
    def draw(self):
        # this draws the circle and the rectangles that are needed for this specific game
        # -self is the Game to draw
        
        self.surface.fill(self.surface_color)
        self.tile_left.draw()
        self.tile_right.draw()
        self.display_score_match()
        self.display_score_mismatch(self.surface_width)
        pygame.display.update() # makes the updated surface appear on the display
               
        
    
    def update(self):       
        current_time  = pygame.time.get_ticks()
        if len(self.tile_clicked) == 2 and current_time > self.turn_white_time:
            self.tile_left.set_color(self.default_color)    
            self.tile_right.set_color(self.default_color)
            self.tile_clicked = []
                              
        
    
    def main_handle_events(self):
        # handles each user events by changing the game state appropriately
        # -self is the Game of whose events are handled
        
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT:
                self.close_clicked = True
            if event.type == pygame.MOUSEBUTTONDOWN:
                self.handle_color_change(event)           
                #self.update_score()
        #self.handle_color_change(event)
    
    def display_score_match(self):
        text_string = 'Match: ' + str(self.score[0])
        text_colour = pygame.Color('white')
        text_font = pygame.font.SysFont('Times New Roman',25)
        text_image = text_font.render(text_string, True, text_colour)
        text_pos = [0,0]
        self.surface.blit(text_image, text_pos)
        
    def display_score_mismatch(self, surface_width):
        text_string = 'Mismatch: ' + str(self.score[1])
        text_colour = pygame.Color('white')
        text_font = pygame.font.SysFont('Times New Roman',25)
        text_image = text_font.render(text_string, True, text_colour)
        text_pos = [(surface_width - text_image.get_width()), 0]
        self.surface.blit(text_image, text_pos)    
    
 

    def handle_color_change(self, event):
        
        if len(self.tile_clicked) < 2:         
        
            if 1 not in self.tile_clicked:
                if event.button == 1 and self.tile_left.inside_tile(event.pos) == True:     
                    self.tile_left.set_color(random.choice(self.color_options)) 
                    self.tile_clicked.append(1) 
            
            if 2 not in self.tile_clicked:
                if event.button == 1 and self.tile_right.inside_tile(event.pos) == True:    
                    self.tile_right.set_color(random.choice(self.color_options))             
                    self.tile_clicked.append(2) 
    
            if len(self.tile_clicked) == 2:
                delay_time = 1000 # 1000 milliseconds == 1 second
                self.turn_white_time = pygame.time.get_ticks() + delay_time        
        
        
    def update_score(self):
        if self.tile_left.color_match(self.tile_right) == True:
            self.score[0] = self.score[0] + 1 
        else:
            self.score[1] = self.score[1] + 1 

         
class Tile:
    
    def __init__(self, rect_color, rect_left, rect_top, rect_width, rect_height,surface):
    # Initialize a rectabgle which is used as a paintbrush.
    # - self is the rectangle to initialize
    # - rect_color is the pygame.Color of the dot
    # - rect_height is the int length of the rectangle in the y axis
    # - rect_width is the int width of the rectangle in the x axis
    # - rect_left is the int coordinate position of the rectangle in the x axis
    # - rect_top is the int coordinate position of the rectangle in the y axis
    # - rect_velocity is a list of x and y components and the speed of which the rectangles can move           
    
        self.rect_colour = pygame.Color(rect_color)
        self.rect_height = rect_height
        self.rect_width = rect_width
        self.rect_left = rect_left
        self.rect_top = rect_top 
        self.surface = surface
        self.rect_parameters = pygame.Rect(rect_left, rect_top, rect_width, rect_height)        
    
    def draw(self):
        # draws the rectangle on the surface
        # - self is the rectangle
        
        pygame.draw.rect(self.surface, self.rect_colour, self.rect_parameters)
        
            
    def inside_tile(self, position):
        inside = False
        if self.rect_parameters.collidepoint(position):
            inside = True
        return inside
    
    def set_color(self, color):
        self.rect_colour = pygame.Color(color)
    
    def color_match(self, other_tile):
        match = False 
        if self.rect_colour == other_tile.rect_colour:
            match = True
        return match

main()


来源:https://stackoverflow.com/questions/65047229/time-delay-and-keeping-track-of-the-of-of-click

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!