Python Pygame:函数使用时间轮询REST响应。睡眠延迟冻结游戏窗口

Python Pygame:函数使用时间轮询REST响应。睡眠延迟冻结游戏窗口,python,rest,pygame,wait,sleep,Python,Rest,Pygame,Wait,Sleep,实际上,我正在编写一个多用户pygame游戏,其中客户端通过REST请求与服务器通信。我得到了一个函数,在这个函数中,游戏必须等待另一个玩家进入服务器上的“队列”,才能开始一个新游戏。为此,我使用get请求(使用请求完成)轮询服务器,中间有一个time.sleep-delay。但这次,睡眠也会导致我的游戏循环停止,并在等待时冻结我的游戏窗口。但是我想让用户在等待期间离开游戏队列。这是不可能的,因为我的屏幕被冻结,变成了“离开队列”对话框,用户无法单击此按钮或右上角的“x”离开队列 我已经尝试以线

实际上,我正在编写一个多用户pygame游戏,其中客户端通过REST请求与服务器通信。我得到了一个函数,在这个函数中,游戏必须等待另一个玩家进入服务器上的“队列”,才能开始一个新游戏。为此,我使用get请求(使用请求完成)轮询服务器,中间有一个time.sleep-delay。但这次,睡眠也会导致我的游戏循环停止,并在等待时冻结我的游戏窗口。但是我想让用户在等待期间离开游戏队列。这是不可能的,因为我的屏幕被冻结,变成了“离开队列”对话框,用户无法单击此按钮或右上角的“x”离开队列


我已经尝试以线程的形式启动轮询功能,但这并不能解决屏幕冻结/游戏循环停止的问题。

关于如何实现此功能的几个关键点:

  • 在一个线程中处理所有套接字I/O
  • 发生套接字事件时发送回主循环
  • 不要睡觉或延迟pygame主事件循环。永远
下面是一个套接字侦听器线程示例,它将事件发回pygame主线程。我对代码的长度表示歉意,但我想回答一些功能完整的问题

import threading
import pygame
import random
import enum
import socket
import select
import time


### Event types that are sent to the main event loop
class NetworkEvents( enum.IntEnum ):
    EVENT_HANGUP    = pygame.USEREVENT + 1
    EVENT_COMMAND   = pygame.USEREVENT + 2


### Socket-listener thread that reads commands from the server
### and does the parsing and posting of commands to the main event-loop
class ConversationHandlerThread( threading.Thread ):
    """ A thread that handles a conversation with a single remote server.
        Accepts commands of 'close', 'red', 'green' or 'blue', and posts messages
        to the main PyGame thread for processing """
    def __init__( self, server_address, server_port ):
        threading.Thread.__init__(self)
        self.server_address = server_address
        self.server_port    = server_port
        self.server_socket  = None
        self.data_buffer    = ''
        self.daemon         = True # exit with parent
        self.done           = False

    def stop( self ):
        self.done = True

    def connect( self ):
        self.server_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
        while True:
            try:  
                self.server_socket.connect( ( self.server_address, self.server_port ) )
                break;
            except:
                print( "Failed to connect %s:%d, will retry" % ( self.server_address, self.server_port ) )
                time.sleep( 12 )

    def run( self ):
        """ Connects to Server, then Loops until the server hangs-up """
        self.connect()

        # Now we're connected, start reading commands
        read_events_on   = [ self.server_socket ]
        while ( not self.done ):
            # Wait for incoming data, or errors, or 0.5 seconds
            (read_list, write_list, except_list) = select.select( read_events_on, [], [], 0.5 )

            if ( len( read_list ) > 0 ):
                # New data arrived, read it
                incoming = self.server_socket.recv( 8192 )
                if ( len(incoming) == 0):
                    # Socket has closed
                    new_event = pygame.event.Event( NetworkEvents.EVENT_HANGUP, { "address" : self.server_address } )
                    pygame.event.post( new_event )
                    self.server_socket.close()
                    self.done = True
                else:
                    # Data has arrived
                    try:
                        new_str = incoming.decode('utf-8')
                        self.data_buffer += new_str
                    except: 
                        pass # don't understand buffer

                    # Parse incoming message (trivial parser, not high quality) 
                    # commands are '\n' separated
                    if (self.data_buffer.find('\n') != -1 ):
                        for command in self.data_buffer.split('\n'):
                            command = line.strip()
                            # client disconnect command
                            if ( command == 'close' ):
                                new_event = pygame.event.Event( NetworkEvents.EVENT_HANGUP, { "address" : self.server_address } )
                                pygame.event.post( new_event )
                                self.server_socket.close()
                                self.done = True

                            # only make events for valid commands
                            elif ( command in ( 'red', 'green', 'blue' ) ):
                                new_event = pygame.event.Event( NetworkEvents.EVENT_COMMAND, { "address" : self.server_address, "message" : command  } )
                                pygame.event.post( new_event )
                        self.data_buffer = ''  # all used-up


### MAIN

# Start the connection-listener thread
thread1 = ConversationHandlerThread( '127.0.0.1', 5555 )
thread1.start()
线程运行后,将在主循环中接收事件,与任何其他PyGame事件相同:

# Main paint / update / event loop
done = False
while ( not done ):
    SPRITES.update()

    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True

        elif ( event.type == NetworkEvents.EVENT_HANGUP ):
            print(" CLIENT DISCONNECTED %s " % ( str(event.address) ) )

        elif ( event.type == NetworkEvents.EVENT_COMMAND ):
            print(" CLIENT MESSAGE FROM %s - %s " % ( str(event.address), event.message ) )
            if ( event.message == 'red' ):
                new_sprite = AlienSprite( RED )
                SPRITES.add( new_sprite )
    # ... etc.

如果您的套接字I/O在线程中处理,并且主事件循环从不休眠,那么您应该能够使用PyGame制作一个流畅的程序。保持您的网络流量小而简洁。

嘿,金斯利,谢谢您的详细回答。因为我必须使用REST通信(这是一个给定的要求)。我不确定这种方法是否适合我。但是你关于使用userevents的提示给了我一个不同的想法,我将尝试一下。我不久前用过,但我完全忘了:)