0
\$\begingroup\$

I have decided to try out pygame. I created a class that is supposed to handle all the GUI and game related stuff.

My idea is that I would have two seperate threads. One to handle the GUI and one to handle all the calculations the game does in the background.

import threading
import pygame
import pygame_gui


class Game ():


    engine_running = True
    gui_running = True
    clock = pygame.time.Clock()

    gui_framerate = 60.0
    engine_framerate = 120.0

    def __init__(self):

        pygame.init()
        pygame.display.set_caption('Explodotech')
        self.window_surface = pygame.display.set_mode((800, 600))
        self.background = pygame.Surface((800, 600))
        self.background.fill(pygame.Color('#000000'))

        self.manager = pygame_gui.UIManager((800, 600))

        ### Define GUI Elements here

        self.quit_button = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((650, 500),
                        (100, 50)), text='Quit', manager=self.manager,                         
                        tool_tip_text = "Quit the game")

        ### Create and start the threads
        self.gui_thread = threading.Thread(target = self.gui_loop)
        self.engine_thread = threading.Thread(target = self.engine_loop, args = [])

        self.gui_thread.start()
        self.engine_thread.start()


    def start_polling(self):
        """Starts the main loop"""
        self.engine_running = True

    def stop_polling(self):
        """Stops the main loop"""
        self.engine_running = False

    def gui_loop(self):
        """Managing all the GUI stuff"""

        print ("GUI-loop started!")

        while self.gui_running:
            print("Polling GUI")
            dT = self.clock.tick_busy_loop(60)/1000.0

            for event in pygame.event.get():

                if event.type == pygame.QUIT:
                    self.gui_running = False

                if event.type == pygame.USEREVENT:
                    if event.user_type == pygame_gui.UI_BUTTON_PRESSED:
                        if event.ui_element == self.quit_button:
                            self.quit_button_event()

                self.manager.process_events(event)

            self.manager.update(dT)

            self.window_surface.blit(self.background, (0, 0))
            self.manager.draw_ui(self.window_surface)

            pygame.display.update()

    def engine_loop(self):
        """Doing all the game calculations in the background"""
        while self.engine_running:
            print(self.clock.tick_busy_loop(1))
        

    ### Define GUI events here

    def quit_button_event(self):
        """Shut down the GUI"""
        print("Quit-button pressed!")
        self.gui_running = False
        self.engine_running = False

Basically what's happening here is that I have two threads one should run the "gui_loop" function the other should run the "engine_loop". However when the gui thread starts and gets into its while-loop it get stuck. The windows goes unresponsive and I have to force windows to shut it down. However if I a create a Game-object and call the function directly it all works fine (obviously commenting out the party where I create the Thread-object):

g = Game()
g.gui_loop()

Any pointers what I am doing wrong would be greatly appreciated!

\$\endgroup\$
3
  • \$\begingroup\$ This past Q&A suggests that your event loop should be on the main thread (where __init__ is called), rather than on a separate thread. Does changing where you do the event polling have any impact in your case? \$\endgroup\$ – DMGregory Nov 9 '20 at 18:31
  • \$\begingroup\$ not really... I think... I am still at the very beginning and would like to understand whats happening (or why it's NOT happening). But I will still be able to feed data into the gui from the other thread, right? \$\endgroup\$ – bertibott Nov 9 '20 at 18:45
  • 1
    \$\begingroup\$ You should start by doing everything on a single thread. That's the typical game loop; it spins until the game exits, and in each cycle you fetch inputs, update the game world, draw the game, and draw the GUI on top, over and over again, all on one thread. If there's more then one thread, then you have to worry about synchronization problems. And if it's not done carefully, it may actually be slower because of context switching, locking, etc. Then there are these platform-specific concerns about GUI rendering. All that makes things needlessly harder. \$\endgroup\$ – Filip Milovanović Nov 10 '20 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.