Pygame: функция опроса для ответа REST с time.sleep задержка останавливает окно игры - PullRequest
1 голос
/ 28 января 2020

Я на самом деле программирую многопользовательскую игру-пигмент, в которой клиенты общаются с сервером через REST-запросы. У меня есть функция, при которой игра должна ждать, пока другой игрок не войдет в свою «очередь» на сервере, чтобы начать новую игру. Я сделал это путем опроса сервера с моим get-Request (выполненным с помощью Requests) с промежуточной задержкой time.sleep. Но на этот раз. Сон останавливает мою игру-l oop и останавливает окно игры во время ожидания. Но я хочу предложить пользователю покинуть игровую очередь во время ожидания. Это невозможно, потому что мой экран завис и превращается в диалог «Выход из очереди», который не отображается, и пользователь не может нажать эту кнопку или даже «x» в правом верхнем углу, чтобы покинуть очередь.

Я уже пытался запустить функцию опроса как поток, но это не исправляет зависание экрана / остановка игры l oop.

1 Ответ

1 голос
/ 29 января 2020

Несколько ключевых моментов о том, как заставить это работать:

  • Обработка всех ваших операций ввода-вывода сокета в потоке
  • Отправка События Pygame назад к основное l oop когда происходят события сокетов
  • Не спите и не задерживайте ваше главное событие пигмея-l oop. Ever.

Вот пример потока Socket-Listener, который отправляет события обратно в основной поток 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()

После запуска потока события принимаются в основном l oop, так же, как любое другое событие 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.

Если ваш ввод-вывод сокета обрабатывается в потоке, а главное событие -l oop никогда не спит, вы должны иметь возможность создавать хорошо работающую программу с PyGame. Сделайте свой сетевой трафик c маленьким и лаконичным.

...