首页 > 解决方案 > Pygame的while循环中单线程的窗口冻结

问题描述

我正在编写一个短程序来显示卡片。我怀疑是代码的长度阻止了 P3 上的最终“OK”提交(最后一个玩家的提交)正确执行:此时程序有时会评估获胜者并清除回合,但大多数时候相反会冻结。我试过clock.tick(low 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()

标签: pythonpython-3.xpygame

解决方案


我认为是时候进行代码清理了,然后你的问题就会消失(或者你会找到它)。

目前主循环是事件处理、屏幕绘制和游戏引擎的大混合。尝试将这些部分分开。

将一些循环内处理移到函数中——比如if ok_clicked_2:. 创建一个存储游戏状态的数据结构可能会有所帮助,然后让事件更改该游戏状态。当需要将游戏绘制到屏幕上时,绘制代码可以查询状态,并采取相应的行动。

就您的实际锁定而言,如果self.game.get_play_in_turn() == NUM_PLAYERS没有在屏幕上绘制任何内容。这是故意的吗?在代码中添加一些print()s,以便您了解执行流程(或学习使用 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()and的调用可能会更好pygame.event.clear()。你不需要这些。


推荐阅读