Automatic condition for a variable.

1

I created a character for a game using a class and within that class I put the attribute life = 10. During the course of this character, it receives some damage from enemy attacks damage which I sub. When that life reaches 0 this character dies.

During all my code, when the character is attacked I have to create an if condition (if life < = 0: print). else: (...)

Is there a way I can assign this condition only once to this attribute? I just wanted this to be able to slow down and organize my code, but every time the character is attacked I have to create the condition again.

Hugs and hope you understand!

    
asked by anonymous 08.03.2018 / 01:44

1 answer

2

There is, you have to be using classes. You practically did not put any code, but if it is ok, you access life in the code using self.life (or if it is outside the methods of the class itself, nome_do_objeto.life )

Well, what happens in Python is that there is a way to define that some attributes are properties : instead of simply storing the value, Python automatically calls a method each time you want to read or write a value in the attribute.

The most normal modern usage of the property is as a decorator of the read value method you want for the attribute. Then the method itself can be used as a decorator for the method of writing in the attribute. But this way is more confusing to understand at first - for didactic purposes, I will first demonstrate the old way of using the property: you pass the "getter" and "setter" function as parameters, and it returns the object that will be used as "smart attribute".

class Jogador:  # em geral
    def __init__(self, ...):
         self.life = 10
         ...

    def set_life(self, value):
        self._life = value
        if self._life <= 0:
             print("Você morreu") 
             # Mas melhor que usar o print, é fazer raise em 
             # uma exceção customizada - veja abaixo
             ...

    def get_life(self):
        return self._life

    life = property(get_life, set_life)

Ready - can test with this class - every time someone tries to put a value equal to zero or negative in life , it will do the print. Note that it still needs to save the actual value somewhere - per use we use the attribute name with a prefix "_": the self._life in the case functions as a normal Python attribute - but all the code that is written, should use self.life - and then the code from the two above functions is executed. (including if you use the increased assignment operators, of type self.life -= 1 )

The property is a built-in Python constructor that returns a special object, which when associated with an attribute within a class gains those properties. Anyone who wants to understand the details of how this works internally should look at the Python descriptor protocol.

So, there are two more cool things to talk about: the first is to use the property as it is used "modernly" with the decorator syntax.

And the second is - see that in this code we can print that the "player" has died, but the game will continue to function normally - until you find an "if" that verifies life; Ideally, when the method detects that life has dropped below zero, you want to get out of the main game routine, and go to a "game end" screen (or code that subtracts a "continue", etc.). .) - For this, we make use of the exception mechanism of Python - the same that is normally used by the lignaugem when there is an error. In this case, we make a controlled use of it - first by creating a specific exception for "GameOver", and then running the game's main code inside a try / except block.

All together, looks something like this:

class GameOver(Exception):
    pass  
    # Isso mesmo - basta herdar de exception e não fazer mais nada
    # "GameOver" agora pode ser usado com o comando Except.

class Jogador:
    def __init__(self, ...):
         self.life = 10
         ...
    @property
    def life(self):
        return self._life

    @life.setter
    def life(self, value):
        self._life = value
        if self._life <= 0:
             raise GameOver

def principal():
   jogador = Jogador()
   while True:
       # aqui vai o código principal do seu jogo
       # quando o jogador morrer, a execeção vai fazer
       # o programa sair desse while, e cair dentro
       # do bloco "except GameOver" abaixo. 

def controle():
   continua = "s"
   while continua == "s":
       try:
           principal()
       except GameOver:
           print("Você morreu!")
           continua = input("Jogar de novo? (s/n) :")

controle()

Note that the same structure would also work for a game in graphical mode using pygame, for example. Other graphical libraries, such as pyglet, or even tkinter, pygtk, and pyqt, work in a different scheme with events and callbacks - in these cases, your program would not have a while True like above - the graphical library itself has a main loop of her, where she checks events. And instead of using exceptions to control the flow of the program, you use the mechanisms of "events" - each such library will have an event system. The "property" works the same way, but instead of "Raise" you add a "GameOver" event - which should be handled appropriately.

    
08.03.2018 / 03:22