问题
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