2

I would know what is the best way to make multiple loops inside my pygame project. This is all loops I would have :

load loop
game loop
main loop
setting loop
pause loop

but is this the best way to do this ?

This is what my code look like

run = True
while run :
   # do load loop

def main():
   run = True
   while run :
      if loop == 'main' :
         run2 = True
         while run2 :
             # pygame loop

      if loop == 'pause' :
         run2 = True
         while run2 :
            # other loop
...

if __name__ == '__main__' :
   main()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174

1 Answers1

3

Why do you need multiple nested loops? A variabel which stores the current state of the game is sufficient:

def main():
    gamestate = 'load'
    run = True
    while run:

        if gamestate == 'load':
            # [...]

        elif gamestate == 'game':
            # [...]

        # [...]
            # [...]

        pygame.display.flip()

if __name__ == '__main__' :
    main()

If you want to switch the state of the game, then all you have to do is change the variable gamestate.
One main loop which runs the game is all you need. That what happens in the loop, may vary, dependent on the current state of the game. But it is always the same loop, which handles the events, clears the display, draws the scene and finally updates the display.

Note, you can even define functions which do the different parts of the game, but you don't need a loop in the functions:

def load(events):
    # [...]

def game(events):
    # [...]

def main():
    gamestate = 'load'
    run = True
    while run:

        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT:
                run = False

        # [...]

        if gamestate == 'load':
            load(events)

        elif gamestate == 'game':
            game(events)

        # [...]
            # [...]

        pygame.display.flip()

if __name__ == '__main__' :
    main()

Or even in a class:

class MyGame:
    def __init__(self):
        self.gamestate = 'load'
        self.run = True
        self.events = []

    def load(self):
        # [...]

    def game(self):
        # [...]

    def main(self):
        while self.run:

            self.events = pygame.event.get()
            for event in self.events:
                if event.type == pygame.QUIT:
                    self.run = False

            # [...]

            if self.gamestate == 'load':
                self.load()
            elif self.gamestate == 'game':
                self.game()
            # [...]
                # [...]

            pygame.display.flip()

if __name__ == '__main__' :
    app = MyGame()
    app.main()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • wihout the `if __name__ == '__main__' : main()` or inside it ? –  Sep 12 '19 at 14:09
  • @Edhyjox I would prefer to use a `main` function. Note, you can even create a application class with a `run` or `main` method. – Rabbid76 Sep 12 '19 at 14:12
  • Is it best to do it in a class ? –  Sep 12 '19 at 14:19
  • @Edhyjox I would use a class. Note, you can store data to instance attributes (like `self.gamestate` or `self.events`) and you don't need to add a lot of general parameters to the methods of the class, because you can access the attributes in other methods. – Rabbid76 Sep 12 '19 at 14:22
  • @Edhyjox You can put the loop in the constructor (`__init__`) . – Rabbid76 Sep 12 '19 at 14:28
  • Why the indirection via a string in `gamestate`? Why not simply using the functions or methods directly as state? – BlackJack Sep 12 '19 at 16:30
  • @BlackJack May be, but why not a class for each game state rather than a method? The question started with some wired nested loops. I tried to guide to a more comprehensive approach. But I agree, this is not the end and can still be improved. – Rabbid76 Sep 12 '19 at 17:03
  • A class for each state would make this more complex whereas eliminating the indirection via string values would make it simpler. If staying with constants for the states I would actually replace the string literals with an `enum.Enum`. Also a callable would _also_ allow to implement single states (or all of them) as classes without the need to change the dispatcher as you can implement the `__call__()` method or use a method as callable for the state. – BlackJack Sep 13 '19 at 22:29
  • @BlackJack *"A class for each state would make this more complex "* I strongly disagree. That depends on the complexity of the program. In a huge application it would make sense to implement a module for each game state. Of course I agree to replacing the string literals. But I don't think that I need to be instructed, I'm a developer for a quarter of a century. It is the questioner who needs some guidance and hints. – Rabbid76 Sep 14 '19 at 05:52
  • I meant this example. Throwing in classes for states would make this example more complex. If that number in your user name is your birth year then I'm a bit older. Also a developer. But age and experience doesn't change facts. Yes it's for the questioner and I think they might want to know that an indirection via strings for states can be replaced by directly using callables (functions, methods, any callable object) as states. – BlackJack Sep 14 '19 at 23:07
  • @BlackJack Ok now I agree. For this example it would overcomplicate this example. And of course directly callable functions will be the next step of improvement. – Rabbid76 Sep 15 '19 at 06:25