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

ercv8c1e  于 2022-12-21  发布在  Python
关注(0)|答案(2)|浏览(255)

我想写一个gomoku game的服务器端和客户端。终端版本的工作很好,但pygame版本只是阻塞,不能渲染任何东西。
下面是游戏执行函数

  • 首先它启动一个套接字连接
  • init中的self._running = True,从服务器获取的包类似于{"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()

并在中间调用on_event函数接受用户的下一步动作

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

编码如下

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))

我的尝试:

  • 我在on_eventprint(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))

结果是包运行正常但是GUI仍然阻塞,即使我在while循环中添加了sleep,它也仅在gameover时呈现
我是新的python多线程和pygame与套接字,我写了一个只是pygame部分,它的工作很好,所以终端+套接字。

k5ifujac

k5ifujac1#

通常Pygame和其他GUI框架中的这类问题来自于主线程所扮演的特殊角色。
Pygame通过一个事件队列来处理它所有的事件消息。这个模块中的例程帮助你管理那个事件队列。输入队列严重依赖于pygame. displayypgame模块来控制显示窗口和屏幕模块。如果显示器还没有初始化并且没有设置视频模式,事件队列可能无法正常工作。**应该从主线程调用事件子系统。**如果您想将事件从其他线程发送到队列中,请使用pygame.fasteventpygame模块与事件和队列模块交互.

vlju58qv

vlju58qv2#

你正在从一个应答队列中阅读一个参数block=True,这意味着它阻塞了整个while循环,并且on_render调用也被reply_q.get(True)阻塞了,所以如果你不经常给reply_q消息,你的屏幕就不会被重新呈现,顺便说一下,你的事件处理代码也会被阻塞。
docs.python#Queue.get

相关问题