pygame多线程客户端套接字GUI阻塞

Ari*_*ere 9 python sockets user-interface pygame blocking

我想用服务器和客户端写一个gomoku游戏,终端版本运行良好,但pygame版本刚刚被阻止,无法兑换任何东西

这是游戏执行功能

  • 首先,它启动套接字连接

  • self._running = Trueinit,从服务器获取包就像{"grid":GRID(strings with 0 and 1), "x":X, "y":Y, "player":LAST_PLAYER, "next_player":CURRENT_PLAYER, "gameover":IS_GAMEOVER}

  • 在循环中:

    • 解析包
    • 检查gameover,如果是,显示有关gameover的信息并关闭套接字
    • 如果当前播放器是我,请调用on_event并让用户移动(我怀疑这一步是错误的,所以解析包步骤阻止了主线程?但是我应该怎么解决这个问题)然后将新的移动包发送到服务器
    • 如果当前的播放器不是我,那么发送一个特殊的包给我正在等待的服务器(我知道这有点愚蠢)

这就像循环一样

        while self._running:
            data = self.client_thread.reply_q.get(True)

            if data:
                self.last_player = data["player"]
                self.grid = self.grid_str_2_matrix(data["grid"])
                self.lastPosition = [data["x"], data["y"]]
                self.gomoku_board_init()

                if data["gameover"] == -1:
                    if data["next_player"] != self.player:
                        self.client_thread.cmd_q.put(ClientCommand(ClientCommand.SEND, {"wait": True}))
                        print("waiting")
                    else:
                        for event in pygame.event.get():
                            self.on_event(event)

                        print("new move")
                else:
                    print("game over")
                    self._running = False
                    if data["gameover"] == 0:
                        self.winner = 0
                    else:
                        self.winner = data["player"]
                    self.client_thread.cmd_q.put(ClientCommand(ClientCommand.CLOSE))
                    break
            self.on_render()
        self.on_cleanup()
Run Code Online (Sandbox Code Playgroud)

on_event在中间调用该函数以加强用户的下一步动作

if data["gameover"] == -1:
    if data["next_player"] != self.player:
        ...
    else:    
        for event in pygame.event.get():
            self.on_event(event)
Run Code Online (Sandbox Code Playgroud)

代码就是这样

def on_event(self, event):
    print(event.type == pygame.MOUSEBUTTONUP)


    if event.type == pygame.MOUSEBUTTONUP:
        pos = pygame.mouse.get_pos()
        r = (pos[0] - PADDING + WIDTH // 2) // (WIDTH + MARGIN)
        c = (pos[1] - PADDING + WIDTH // 2) // (WIDTH + MARGIN)
        print(r, c)
        if 0 <= r < self.board_row and 0 <= c < self.board_column and self.grid[r][c] == 0:
            self.grid[r][c] = self.player
            data = {"grid":self.grid, "x":r, "y":c, "player":self.player}
            self.client_thread.cmd_q.put(ClientCommand(ClientCommand.SEND, data))
Run Code Online (Sandbox Code Playgroud)

我尝试过的:

  • 我添加了一个打印on_event print(event.type == pygame.MOUSEBUTTONUP),当然MOUSEBUTTONUP从未发生过(但我想知道为什么?)

  • 所以我决定使用随机输入跳过这个

代码如下

#for event in pygame.event.get():
#    self.on_event(event)
x, y = self.random_position()
self.grid[x][y] = self.player
data = {"grid":self.grid, "x":x, "y":y, "player":self.player}
self.client_thread.cmd_q.put(ClientCommand(ClientCommand.SEND, data))
Run Code Online (Sandbox Code Playgroud)

结果是包没问题但是 GUI仍然阻塞,甚至我sleep在while循环中添加,它只在以后呈现gameover

我是python多线程的新手,也是带插槽的pygame,我写了一个正常的pygame部分,它工作得很好,终端+套接字也是如此.

Bas*_*hur 0

通常 Pygame 和其他 GUI 框架中的此类问题来自主线程的特殊角色。引用pygame 的文档

Pygame 通过事件队列处理所有事件消息传递。本模块中的例程可帮助您管理该事件队列。输入队列严重依赖 pygame.displaypygame 模块来控制显示窗口和屏幕模块。如果显示器尚未初始化且视频模式未设置,事件队列可能无法正常工作。事件子系统应该从主线程调用。如果您想从其他线程将事件发布到队列中,请使用 pygame.fasteventpygame 模块与事件和队列模块进行交互。