There is, you just have to be using classes. You have virtually not put any code, but if it is ok, you access life in the code using self.life
(or if it is outside the class’s own methods, nome_do_objeto.life
)
Well, what happens in Python is that there’s a way to define some attributes 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 use of the Property is as a decorator of the method of read value you want for the attribute. Then the method itself can be used as a decorator for the method of writing to the attribute. But this way is more confusing to understand at first - for didactic purposes, I will first demonstrate the old way of using Property: you pass the "getter" and "Setter" function as parameters, and it returns the object that will be used as "intelligent 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 do tests with this class - each time someone tries to put a value equal to zero or negative in life
, He’s gonna do the print. Note that it still needs to store the real value somewhere- by usual we use the attribute name with a "_" prefix: the self. _life in the case works as a normal Python attribute - but any code that is written must use self.life - and then the code of the two little functions above is executed. (including if you use the increased assignment operators, of the type self.life -= 1
)
"Property" is a built-in Python constructor that returns a special object, which when associated with an attribute within a class gains these properties. Anyone who wants to understand the details of how this works internally should seek to read about Python’s "Descriptor Protocol".
So, there are two other cool things to talk about: the first is to use the Property as it is used "modernamente", with the syntax of decorators.
And the second is - note that in this code we can make the print that the "player" died, but the game will continue functioning normally - until we find an "if" that checks life;
The ideal is that when the method detects that life has dropped below zero, you want to leave the main routine of the game, and go to an "end of game" screen (or the code that subtracts a "continue", etc...) - For this, we make use of the Python exception mechanism - the same that is normally used by the ship 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 by running the game’s main code within a Try/except block .
All together, it goes 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 graphic mode using pygame, for example.
Other graphic libraries, like pyglet, or even Tkinter, pygtk, and pyqt, work in a different scheme, with events and callbacks - in such cases, your program would not have a while True
like the one above - the graphical library itself has a main tie to it, where it checks events. And then, instead of using exceptions to control the program flow, you use the "events" mechanisms - every such library will have an event system. "Property" works the same way, but instead of "Raise", you add a "Gameover" event - which should be handled appropriately.