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:
functions nested within functions (with an appropriate object, all variables that small functions need can be object attributes)
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()
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.
– Woss
Confirming what @Andersoncarloswoss said, and adding: Python only works if everything is at the right level of identation
– Jefferson Quesado
I know I only lost a level of identation when I taped
– Matheus Silva Pinto
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
– Matheus Silva Pinto
And there is a need to define these functions within the
main
? What reasoning did you use here?– Woss
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?
– Matheus Silva Pinto
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.
– Woss
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
– Matheus Silva Pinto
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– Jefferson Quesado