我正在尝试创建多个按钮,每个按钮在Pygame中都包含2个矩形。但是,该程序可能会在某个步骤中停留一秒钟,这可能是由于嵌套循环造成的。 特别是,只有在第一次执行时,在主循环中由代码围栏标记的“ while循环”才可以正常工作。如果在第一次之后执行,程序将停止响应一秒钟。反正有没有纠正? 我目前正在10 64位窗口,Python 3.7.4,PyGame 1.9.6上对其进行测试。
import pygame
import time
import random
pygame.init()
# Screen for displaying everything
display_width = 1200
display_height = 700
game_display = pygame.display.set_mode((display_width,display_height),pygame.RESIZABLE)
pygame.display.set_caption('Currently testing')
# Color for later use
red = (200,0,0)
green = (0,200,0)
bright_red = (255,0,0)
bright_green = (0,255,0)
black= (0,0,0)
white= (225,225,225)
grey = (166,166,166)
font_color= black
background_color= white
def create_button(x,y,w,h,name,callback):
# lower part of the button
button_upper= pygame.Rect(x, y, w, h)
# upper part of the button
button_lower= pygame.Rect(x, y+ h, w, h)
# define the area of the button for later interaction
interactable= pygame.Rect(x, y, w, 2*h)
button_info= {'button_lower':button_lower,
'button_upper':button_upper,
'button_name':name,
'interaction':interactable,
'button function':callback,
'color_upper':red, 'color_lower':green}
return button_info
def draw_button(button_info):
# Drawing lower part of the button
pygame.draw.rect(game_display,
button_info['color_lower'],
button_info['button_lower'])
# Drawing upper part
pygame.draw.rect(game_display,
button_info['color_upper'],
button_info['button_upper'])
# Text object for later use
def text_object(text,font):
textSurface= font.render(text,True,font_color)
return textSurface, textSurface.get_rect()
def central_text(text,size,pos):
largeText = pygame.font.Font('freesansbold.ttf',size)
textSurface, textRect = text_object(text,largeText)
textRect.center = (pos)
game_display.blit(textSurface,textRect)
def main():
# The function of the button, temporarily
def print_name():
nonlocal button
nonlocal done
game_display.fill(background_color)
central_text('Button'+' '+button['button_name']+' '+'clicked',80,(display_width/2,display_height/2))
pygame.display.update()
time.sleep(3)
done= True
# function of non-interactable block
def do_nothing():
pass
# Actually create those button
button_1= create_button(display_width*0.3,display_height*0.5,40,40,'1',print_name)
button_2= create_button(display_width*0.35,display_height*0.5,50,50,'2',print_name)
button_3= create_button(display_width*0.4,display_height*0.5,30,30,'3',print_name)
button_4= create_button(display_width*0.45,display_height*0.5,20,20,'4',print_name)
button_5= create_button(display_width*0.5,display_height*0.5,40,30,'5',print_name)
button_6= create_button(display_width*0.55,display_height*0.5,50,40,'6',print_name)
button_7= create_button(display_width*0.6,display_height*0.5,50,30,'7',print_name)
button_8= create_button(display_width*0.65,display_height*0.5,50,50,'8',print_name)
button_9= create_button(display_width*0.7,display_height*0.5,30,40,'9',print_name)
button_10= create_button(display_width*0.75,display_height*0.5,60,70,'10',print_name)
# Create non-interactable rectangles
block_1= create_button(display_width*0.75,display_height*0.8,40,40,'10',do_nothing)
block_2= create_button(display_width*0.7,display_height*0.8,40,40,'9',do_nothing)
block_3= create_button(display_width*0.7,display_height*0.8,40,40,'8',do_nothing)
# Select and store those button in different list, with a non-interactable
# rectangles in each list
list_1=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, button_9, button_10]
list_2=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, block_3, button_9, button_10]
list_3=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, block_2, button_10]
list_4=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, button_9, block_1]
# Attempt to control how many times and in what sequence those
# button list would be used
index= [1,1,2,2,2,3,3,4,4]
random.shuffle(index)
text=' ' # a text that would accompany all the buttons
for i in range (len(index)):
done = False
if index[i] == 1:
button_list= list_1
text= 'text 1'
elif index[i] == 2:
button_list= list_2
text= 'text 2'
elif index[i] == 3:
button_list= list_3
text= 'text 3'
else:
button_list= list_4
text= 'text 4'
# display message 1
game_display.fill(background_color)
central_text('test_text 1',80,(display_width/2,display_height/2))
pygame.display.update()
time.sleep(2)
# display message 2
game_display.fill(background_color)
central_text('test_text 2',80,(display_width/2,display_height/2))
pygame.display.update()
time.sleep(3)
'''This is where the program would stuck for a second'''
game_display.fill(background_color)
central_text(text,30,(display_width/2,display_height*0.2))
while not done:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.display.quit()
pygame.quit()
quit()
# block that would be executed when left mouse button is pressed
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for button in button_list:
if button['interaction'].collidepoint(event.pos):
button['button function']()
elif event.type == pygame.MOUSEMOTION:
# When the mouse gets moved, change the color of the
# buttons if they collide with the mouse.
for button in button_list:
if not button['button function']== do_nothing:
if button['interaction'].collidepoint(event.pos):
button['color_upper']= red
button['color_lower']= green
else:
button['color_upper']= bright_red
button['color_lower']= bright_green
for button in button_list:
# Turn non-interactable blocks into grey
if button['button function']== do_nothing:
button['color_upper']= grey
button['color_lower']= grey
draw_button(button)
pygame.display.update()
'''the block above would some times stucks the program'''
main()
答案 0 :(得分:0)
市长的问题是,当您延迟并显示更新时,您希望通过pygame.event.pump()
或pygame.event.get()
处理事件。当您使用pygame时,您应该使用pygame.time.delay()
或pygame.time.wait()。
我建议更改程序。使用1个主循环和1个事件循环。在此循环中执行游戏过程。代替
for i in range (len(index)): # [...] while not done: for event in pygame.event.get(): # [...] # [...]
将过程更改为
done = False
run = True
i = 0
while run:
if done:
done = False
if i < len(index)-1:
i += 1
else:
run = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
# [...]
要实现游戏的不同状态,我建议使用游戏state
。例如:
from enum import Enum
class GameState(Enum):
START = 0
TEXT1 = 1
TEXT2 = 2
RUN = 3
BUTTON = 4
state = GameState.START
使用计时器事件(pygame.time.set_timer()
)切换游戏状态。例如:
clicked_button = None
my_event_id = pygame.USEREVENT + 1
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# timer event
elif event.type == my_event_id:
if state == GameState.TEXT1:
pygame.time.set_timer(my_event_id, 3000)
state = GameState.TEXT2
elif state == GameState.TEXT2:
pygame.time.set_timer(my_event_id, 0)
state = GameState.RUN
else:
pygame.time.set_timer(my_event_id, 0)
state = GameState.START
done = True
if state == GameState.RUN:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for button in button_list:
if button['interaction'].collidepoint(event.pos):
pygame.time.set_timer(my_event_id, 3000)
state = GameState.BUTTON
clicked_button = button
# [...]
根据游戏state
绘制场景:
while run:
# [...]
game_display.fill(background_color)
if state == GameState.START:
pygame.time.set_timer(my_event_id, 2000)
state = GameState.TEXT1
elif state == GameState.TEXT1:
# display message 1
central_text('test_text 1',80,(display_width/2,display_height/2))
elif state == GameState.TEXT2:
# display message 2
central_text('test_text 2',80,(display_width/2,display_height/2))
elif state == GameState.RUN:
central_text(text,30,(display_width/2,display_height*0.2))
# [...]
else:
clicked_button['button function']()
pygame.display.update()
游戏循环和主要游戏过程可能如下所示:
from enum import Enum
class GameState(Enum):
START = 0
TEXT1 = 1
TEXT2 = 2
RUN = 3
BUTTON = 4
def main():
# The function of the button, temporarily
def print_name():
nonlocal clicked_button
central_text('Button'+' '+clicked_button['button_name']+' '+'clicked',80,(display_width/2,display_height/2))
# function of non-interactable block
def do_nothing():
pass
# Actually create those button
button_1= create_button(display_width*0.3,display_height*0.5,40,40,'1',print_name)
button_2= create_button(display_width*0.35,display_height*0.5,50,50,'2',print_name)
button_3= create_button(display_width*0.4,display_height*0.5,30,30,'3',print_name)
button_4= create_button(display_width*0.45,display_height*0.5,20,20,'4',print_name)
button_5= create_button(display_width*0.5,display_height*0.5,40,30,'5',print_name)
button_6= create_button(display_width*0.55,display_height*0.5,50,40,'6',print_name)
button_7= create_button(display_width*0.6,display_height*0.5,50,30,'7',print_name)
button_8= create_button(display_width*0.65,display_height*0.5,50,50,'8',print_name)
button_9= create_button(display_width*0.7,display_height*0.5,30,40,'9',print_name)
button_10= create_button(display_width*0.75,display_height*0.5,60,70,'10',print_name)
# Create non-interactable rectangles
block_1= create_button(display_width*0.75,display_height*0.8,40,40,'10',do_nothing)
block_2= create_button(display_width*0.7,display_height*0.8,40,40,'9',do_nothing)
block_3= create_button(display_width*0.7,display_height*0.8,40,40,'8',do_nothing)
# Select and store those button in different list, with a non-interactable
# rectangles in each list
list_1=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, button_9, button_10]
list_2=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, block_3, button_9, button_10]
list_3=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, block_2, button_10]
list_4=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, button_9, block_1]
# Attempt to control how many times and in what sequence those
# button list would be used
index= [1,1,2,2,2,3,3,4,4]
random.shuffle(index)
text=' ' # a text that would accompany all the buttons
my_event_id = pygame.USEREVENT + 1
done = False
run = True
state = GameState.START
i = 0
clicked_button = None
while run:
if done:
done = False
if i < len(index)-1:
i += 1
else:
run = False
if index[i] == 1:
button_list= list_1
text= 'text 1'
elif index[i] == 2:
button_list= list_2
text= 'text 2'
elif index[i] == 3:
button_list= list_3
text= 'text 3'
else:
button_list= list_4
text= 'text 4'
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
elif event.type == my_event_id:
if state == GameState.TEXT1:
pygame.time.set_timer(my_event_id, 3000)
state = GameState.TEXT2
elif state == GameState.TEXT2:
pygame.time.set_timer(my_event_id, 0)
state = GameState.RUN
else:
pygame.time.set_timer(my_event_id, 0)
state = GameState.START
done = True
if state == GameState.RUN:
# block that would be executed when left mouse button is pressed
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for button in button_list:
if button['interaction'].collidepoint(event.pos):
pygame.time.set_timer(my_event_id, 3000)
state = GameState.BUTTON
clicked_button = button
elif event.type == pygame.MOUSEMOTION:
# When the mouse gets moved, change the color of the
# buttons if they collide with the mouse.
for button in button_list:
if not button['button function']== do_nothing:
if button['interaction'].collidepoint(event.pos):
button['color_upper']= red
button['color_lower']= green
else:
button['color_upper']= bright_red
button['color_lower']= bright_green
# draw
game_display.fill(background_color)
if state == GameState.START:
pygame.time.set_timer(my_event_id, 2000)
state = GameState.TEXT1
elif state == GameState.TEXT1:
# display message 1
central_text('test_text 1',80,(display_width/2,display_height/2))
elif state == GameState.TEXT2:
# display message 2
central_text('test_text 2',80,(display_width/2,display_height/2))
elif state == GameState.RUN:
central_text(text,30,(display_width/2,display_height*0.2))
for button in button_list:
# Turn non-interactable blocks into grey
if button['button function']== do_nothing:
button['color_upper']= grey
button['color_lower']= grey
draw_button(button)
else:
clicked_button['button function']()
pygame.display.update()