[英]Window freeze for single thread in while loop of Pygame
我正在編寫一個短程序來顯示卡片。 我懷疑是代碼的長度阻止了 P3 上的最終“OK”提交(最后一個玩家的提交)正確執行:此時程序有時會評估獲勝者並清除回合,但大多數時候相反會凍結。 我試過clock.tick(低fps)、pygame.event.pump()和pygame.event.clear()。 任何線索將不勝感激。
# Round loop begins. Finish until all hands are empty.
while not self.game.get_is_last_round():
player = self.game.get_player(self.game.get_player_turn())
hand = player.order_hand(player.get_hand(),
self.game.get_round_level(),
self.game.get_round_trump_suit())
ok_clicked_2 = False
pygame.event.pump()
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.deal_running = False
self.is_running = False
pygame.display.quit()
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
play = player.get_play()
click = pygame.mouse.get_pressed(num_buttons=3)
pos = pygame.mouse.get_pos()
# Used DeMorgan's law to resolve error
ok_clicked_2 = (OK1_X < pos[0] < OK1_X + B_W) and (OK1_Y < pos[1] < OK1_Y + B_H) and click[0]
b1, card = self.check_hand(pos, player)
b2, play_card = self.check_play(pos, player)
if b1:
hand.remove(card)
play.append(card)
player.set_play(
player.order_hand(play, self.game.get_round_level(),
self.game.get_round_trump_suit()))
player.set_hand(
player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
if b2:
play.remove(play_card)
hand.append(play_card)
player.set_play(
player.order_hand(play, self.game.get_round_level(),
self.game.get_round_trump_suit()))
player.set_hand(player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
clock.tick(100)
surface.blit(background, (0, 0))
if len(self.game.get_player(0).get_hand()) == 25:
self.game.set_is_first_round(True)
else:
self.game.set_is_first_round(False)
if len(self.game.get_player(0).get_hand()) == 0:
self.game.set_is_last_round(True)
else:
self.game.set_is_last_round(False)
if self.game.get_play_in_turn() != NUM_PLAYERS:
pygame.event.pump()
clock.tick(100)
if len(hand) <= 1:
width = 0
x = (BG_WIDTH - CARD_WIDTH) // 2
elif len(hand) >= 8:
width = (BG_WIDTH - SIDE_W - CARD_WIDTH) // (len(hand) - 1)
x = BG_WIDTH // 2 - (CARD_WIDTH + (width * (len(hand) - 1))) // 2
else:
width = CARD_WIDTH
x = (BG_WIDTH - (CARD_WIDTH * len(hand))) // 2
surface.blit(background, (0, 0))
self.blit_backs()
self.blit_round()
self.show_ok()
self.show_hand(x, ROW3h, width, hand)
self.show_hand(CARD_POSITIONS[0][0], CARD_POSITIONS[0][1], SLIM_WIDTH, play)
if ok_clicked_2:
for card in play:
hand.append(card)
player.set_hand(player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
# If player is first to start a round, he/she has a different validity check.
# (Sets the pattern for the cycle)
if player.get_begins_cycle():
valid = self.game.check_validity(True) # is_first
else:
valid = self.game.check_validity(False) # Is not first to play in the round
if not valid: # Clear holding if invalid
if (play == []) or (player.get_play() == []):
print("\nYou must make a play.\n")
else:
print("Invalid play. Try again.")
if not player.get_begins_cycle():
valid_plays = player.get_valid_plays(self.game.get_pattern(),
self.game.get_round_trump_suit())
print("Valid plays: \n")
for temp_play_idx in range(len(valid_plays)):
temp_play = valid_plays[temp_play_idx]
print("[", end='')
for temp_card_idx in range(len(temp_play)):
valid_plays[temp_play_idx][temp_card_idx].show_card("", '')
if temp_card_idx != len(temp_play) - 1:
print(", ", end='')
print("]")
# Clear the current player's selection and restore hand to its original content
cycle_order = self.game.get_cycle_order()
cycle = self.game.get_cycle()
for player_order in range(len(cycle_order)):
if player == cycle_order[player_order]:
cycle_order.remove(player)
cycle.pop()
self.game.set_cycle_order(cycle_order)
self.game.set_cycle(cycle)
else: # Valid play on submit
# Special case for HIGH_SUIT play, play lowest card if another player has greater
play = self.game.check_high_suit(play)
# If friend card played, establish and print teammates
# TODO: auto-designate friends if the last round
# has been reached (friends buried in treasure case)
# TODO: determine whether friend is "dead"
self.game.check_for_friends()
cycle = self.game.get_cycle()
cycle.append(play)
self.game.set_cycle(cycle)
cycle_order = self.game.get_cycle_order()
cycle_order.append(player)
self.game.set_cycle_order(cycle_order)
# self.clear_positions()
for card in play:
hand.remove(card)
player.set_hand(
player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
self.game.next_player_turn()
self.game.set_play_in_turn(self.game.get_play_in_turn() + 1)
print(self.game.get_play_in_turn())
play = []
else:
self.game.set_play_in_turn(0)
# Distribute any points in the round to round winner
self.update_cycle_points()
for p in self.game.get_players():
for card in p.get_play():
discard = self.game.get_discard()
discard.append(card)
p.set_play([])
pygame.event.clear()
clock.tick(100)
pygame.display.update()
我認為是時候進行代碼清理了,那么您的問題將 go 消失(或者您會找到它)。
目前主循環是事件處理、屏幕繪制和游戲引擎的大混合。 嘗試將這些部分分開。
將一些循環內處理移到函數中 - 例如if ok_clicked_2:
之后的塊。 制作一個存儲游戲狀態的數據結構可能會有所幫助,然后讓事件更改該游戲 state。 當需要將游戲繪制到屏幕上時,繪制代碼可以查詢 state,並進行相應操作。
就您的實際鎖定而言,如果self.game.get_play_in_turn() == NUM_PLAYERS
則不會在屏幕上繪制任何內容。 這是故意的嗎? 在代碼中添加一些print()
以便了解執行流程(或學習使用 python 調試器)。
我認為向前邁出的最大一步是將所有屏幕繪畫移動到主循環的一個部分,例如:
# Render the screen
print( "Rendering Screen" )
surface.blit(background, (0, 0))
self.blit_backs()
self.blit_round()
# etc. for all other things, score, buttons, ...
clock.tick(60)
pygame.display.update()
您似乎可以正常處理事件,因此最好刪除對pygame.event.pump()
和pygame.event.clear()
的調用。 你不需要這些。
按照 Kingsley 的建議,我按 function 組織了代碼:渲染屏幕、游戲引擎和事件處理。 我會按照 Random Davis 的建議提供 MRE,但這將包括 5 個集成文件,這些文件需要很長時間才能削減。
事實證明,問題在於一段單獨調用的代碼:“update_cycle_points()”。 在其中,有一個不包含事件處理程序的 while 循環。 解決方案是將其更改為 for 循環,Pygame 似乎可以正確處理(不會凍結,因為它不希望在那里進行事件處理)。
我還毫無問題地刪除了 pygame.event.clear() 和 pump() 函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.