How to organize pygame code correctly?

Asked

Viewed 502 times

1

I came from Javascript which is a little simpler than Python, there I didn’t need to worry too much about scope (almost everything was global) and not about code organization. But in Python even if it is a language that has a better syntax I can’t organize the code properly, especially when I use pygame. Most of the time the commands will run separate threads so no matter what order I call them, my code is getting pretty messy, has variable being declared then call a function then create a function, then instancio classes all in a sort of arbitrary order, I don’t know how to organize this, example:

def main ():
    def embaralhar ():
        threading.Timer(card_shuffle.get_length() / 4, lambda: dar_cartas(39)).start()
    def dar_cartas (x):
        if x > 33: threading.Timer(card_shuffle.get_length() / 4, lambda: dar_cartas(x - 2)).start()
    os.environ["SDL_VIDEO_CENTERED"] = "1"
    pygame.init()
    open_sans_regular_18 = pygame.font.Font("fontes/open_sans/regular.ttf", 18)
    card_shuffle = pygame.mixer.Sound("sons/card_shuffle.wav")
    tela = pygame.display.set_mode([800, 600], pygame.NOFRAME)
    tela_rect = tela.get_rect()
    pontuacao = "0 x 0"
    placar = passion_one_regular_40.render(pontuacao, True, [255, 255, 255], [0, 0, 0])
    placar_rect = placar.get_rect(centerx = tela_rect.centerx)
    relogio = pygame.time.Clock()
    rodando = True
    embaralhar()
    while rodando:
        for e in pygame.event.get():
    pygame.quit()
main()

Please an efficient tip to organize pre-order when the order does not interfere with the program result.

  • 1

    First, could you correct the indentation of your code in the question? There are several things on the same indentation level, making it impossible to identify the structure of the code.

  • Confirming what @Andersoncarloswoss said, and adding: Python only works if everything is at the right level of identation

  • I know I only lost a level of identation when I taped

  • And the code is not complete there, these functions that appear do much more things just put there to show where I am declaring them

  • And there is a need to define these functions within the main? What reasoning did you use here?

  • I need these functions there to have access to many variables that are inside the main, such as tela_rect, score, etc. I did not want to have to go through many parameters, it would be better to pass parameters?

  • If the function depends on many external variables, it may be an indication that you should define a class. Without the full code and without understanding what the program should do it is difficult to help.

  • It makes sense what you said now, I think that’s exactly what I’m going to do, create a class, now I think I understood what it’s for to create a class, I just created classes when I instantiated several objects, when I was going to instantiate only one or two I didn’t create

  • 1

    You can say that the variables are global using the global, but I don’t think that’s your case. It’s much more appropriate in this case to store in a class like @Andersoncarloswoss said. I organised as follows: https://github.com/jeffque/gravity-system/blob/master/engine.py

Show 4 more comments

1 answer

2


Boy

What you need is object orientation. In the good way, not in the "mandatory" way that is Java, nor in the way "hidden under the semantics of prototyping" that is in Javascript.

You need less:

  1. functions nested within functions (with an appropriate object, all variables that small functions need can be object attributes)

  2. Threads. Although you say "it’s all in separate threads, so I don’t have to worry about order," that’s wrong. It is one thing to want to do things in parallel. It is another to want to play "all at once now without having control of anything".

Just with the two examples you have there of what your "threaded functions" would look like, the chances of you having race-conditions that obliterate the consistency of your game look pretty great.

In Javascript it is simple to always put the "Settimeout" for its function to be called after a while, and it looks like it runs in a parallel thread. It is not - the execution is always in order, the "mainloop" of the browser is that notes the functions recorded with "setTimeout" and other events and calls everything in order.

The pygame is a library notorious precisely for not having a "mainloop" already co-located. It is up to the programmer to write the code that will be executed in all frames, and call the functions and methods of checking everything.

Replace this with threading calls. Timer almost at random is fearful - it could work, but the running program can only be viewed as a spaghetti dusting in a vacuum without even gravity. (Remembering that asynchronous calls in javascript are not threads. Each function called with "Settimeout" will run from start to finish, being able to change other variables without being interrupted. With Threads, you can have an interruption within any expression of the code, between any two lines, and this interruption can change variables you were touching.

Well, if you’re going to continue with pygame, you’ll need to create your own event system. You will learn a lot if you are going to do this, and you will become a better dev. But -- the barrier to having to create this can be great. You can choose to use a framework such as "pyglet" that already has a mainloop, and an event system - and you will have calls that are really equivalent to SetTimeout ready to function without the side effects of threads.

That said, a few tips that might help you: use an object guide as needed.

For the little bit you gave, start with a class (I’m assuming you use Python 3 - if you’re not, approve and switch to Python 3.6 now)

def load_fonts():
    global open_sans_regular_18, ...
    # Esse tipo de recurso só ode ser carregado depois do pygame.init, 
    # no entanto, com o nome "comprido" e como é algo que não muda,
    # pode estar disponível como variável global tranquilamente.

    open_sans_regular_18 = pygame.font.Font("fontes/open_sans/regular.ttf", 18)
    ...

class Jogo:

    def __init__(self):
        os.environ["SDL_VIDEO_CENTERED"] = "1"
        pygame.init()
        load_fonts()
        self.card_shuffle = pygame.mixer.Sound("sons/card_shuffle.wav")
        self.tela = pygame.display.set_mode([800, 600], pygame.NOFRAME)
        self.tela_rect = tela.get_rect()

        self.pontuacao_jogador_1 = 0
        self.pontuacao_jogador_2 = 0


        self.relogio = pygame.time.Clock()
        rodando = True
        embaralhar()

    def desenha_placar(self):
        pontuacao = f"{self.pontuacao_jogador_1} X {self.pontuacao_jogador_2}"
        placar = passion_one_regular_40.render(pontuacao, True, [255, 255, 255], [0, 0, 0])
        placar_rect = placar.get_rect(centerx = self.tela_rect.centerx)
        self.tela.blit(placar_rect, placar)


    def mainloop(self):
        rodando = True
        embaralhar
        while rodando:
            for e in pygame.event.get():
                ...
            self.desenha_placar()
                ...
            if condicao:
                self.embaralhar()
            pygame.display.flip()
            self.relogio.tick()

    def agendar(self, intervalo, funcao, parametros):
        # aqui voce cria seu sistema de eventos - pode ser criando uma lista 
        # onde cada elemento é uma tupla com o "numero de tick" onde o evento deve
        # ser chamado, seguido do objeto chamável e argumentos.
        # a lista pode ser mantida em ordem com a bibliotea "heapq" do Python.
        ...

    def embaralhar (self):
        tempo = self.card_shuffle.get_length() / 4
        self.dar_cartas(39))

    def dar_cartas (x):
        if x > 33: 
            self.agendar(self.card_shuffle.get_length() / 4, 
                         self.dar_cartas, x - 2)

    def quit(self):
        pygame.quit()

if __name__ == "__main__":
    jogo = Jogo()
    try:
        jogo.mainloop()
    finally:
        jogo.quit()
  • 1

    Speaking of threads, take advantage and leave the cue to the AP here that in the famous Unity engine the main processing is done in one thread, on "main loop" Unity itself. If even market giants do this, there must be a good reason for this ;-)

  • Very good, I was well lost I think now I’m beginning to understand

Browser other questions tagged

You are not signed in. Login or sign up in order to post.