Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

5. diel - Bojovník do arény v Pythone

V minulej lekcii, Kvíz - Úvod, konštruktory, atribúty a metódy v Pythone OOP , sme si vysvetlili ako fungujú referencie na objekty. Bude sa nám to hodiť dnes aj nabudúce. Tento a budúci Python tutoriál budú totiž venované dokončenie našej arény. Hracie kocku už máme, ešte nám chýba ďalšie 2 objekty: bojovník a samotná aréna. Dnes sa budeme venovať bojovníkovi. Najprv si popíšme, čo má bojovník vedieť, potom sa pustíme do písania kódu.

Atribúty

Bojovník sa bude nejako menovať a bude mať určitý počet hp (teda života, napr. 80hp). Budeme uchovávať jeho maximálnej život (bude sa líšiť u každej inštancie) a jeho súčasný život, teda napr. Zranený bojovník bude mať 40HP z 80tich. Bojovník má určitý útok a obranu, oboje vyjadrené opäť v hp. Keď bojovník útočí s útokom 20HP na druhého bojovníka s obranou 10hp, uberie mu 10hp života. Bojovník bude mať referenciu na inštanciu objektu Kostka. Pri útoku či obrane si vždy hodí kockou a k útoku / obrane pripočíta padlých číslo. (Samozrejme by mohol mať každý bojovník svoju kocku, ale chcel som sa priblížiť stolové podobe hry a ukázať, ako OOP naozaj simuluje realitu. Bojovníci teda budú zdieľať jednu inštanciu kocky.) Kockou dodáme hre prvok náhody, v realite sa jedná vlastne o šťastie, ako sa útok alebo obrana vydarí. Konečne budeme chcieť, aby bojovníci podávali správy o tom, čo sa deje, pretože inak by z toho užívateľ nič nemal. Správa bude vyzerať napr. "Zalgoren útočí s úderom za 25HP.". Správami sa zatiaľ nebudeme zaťažovať a vrátime sa k nim až nakoniec.

Už vieme, čo budeme robiť, poďme na to! :) Do súboru si pridajme triedu Bojovnik a za moment ju dodáme aj patričné atribúty. Všetky budú privátne.

Metódy

Poďme pre atribúty vytvoriť konštruktor, nebude to nič ťažké. Komentár napíšem len sem, ďalej je vynechám. Nebudem ich písať ani u ďalších metód, aby sa tutoriál zbytočne neroztahoval a zostal prehľadný. Vy si je samozrejme dopíšte.

class Bojovnik:
    """
    Třída reprezentující bojovníka do arény.
    """

    def __init__(self, jmeno, zivot, utok, obrana, kostka):
        """
        jmeno - jméno bojovníka
        zivot - maximální život bojovníka
        utok - útok bojovníka
        obrana - obrana bojovníka
        kostka - instance kostky
        """
        self.__jmeno = jmeno
        self.__zivot = zivot
        self.__max_zivot = zivot
        self.__utok = utok
        self.__obrana = obrana
        self.__kostka = kostka

Všimnite si, že maximálna zdravie si v konstruktoru nastavíme na zdravie. Predpokladáme, že je bojovník pri vytvorení plne zdravý. Stačí nám teda poznať iba jeho život a maximálny život bude rovnaký.

Prejdime k metódam a opäť sa najprv zamyslime nad tým, čo by mal bojovník vedieť. Začnime tým jednoduchším, budeme chcieť nejakú textovú reprezentáciu, aby sme mohli bojovníka vypísať. Prekryjeme teda metódu __str __ (), ktorá vráti meno bojovníka. Určite sa nám bude hodiť metóda, vracajúci či je bojovník nažive. Aby to bolo trochu zaujímavejšie, budeme chcieť kresliť život bojovníka do konzoly, nebudeme teda písať, koľko má života, ale "vykreslíme" ho takto:

[#########    ]

Vyššie uvedený život by zodpovedal asi 70%. Doteraz spomínané metódy nepotrebovali žiadne parametre. Samotný útok a obranu nechajme na neskôr a poďme si implementovať __str __ (), nazive () a graficky_zivot (). Začnime s __str __ (), tam nie je čo vymýšľať:

def __str__(self):
    return str(self.__jmeno)

Sami si skúste vytvoriť metódu __repr __ (). Teraz Implementujte metódu nazive (), opäť to nebude nič ťažké. Stačí skontrolovať, či je život väčšia ako 0 a podľa toho sa zachovať. Ovšem či je bojovník nažive by mohla byť aj jeho vlastnosť. Python obsahuje špecialitu - tzv. Dekorátory. Dekorátory "vylepšujú" metódy. My využijeme dekorátor property, ktorý mení metódu na vlastnosť. Dekorátor sa píše nad deklaráciu funkcie a pred jeho názov sa píše zavináč.

@property
def nazivu(self):
    if self.__zivot > 0:
       return True
    else:
       return False

Keďže aj samotný výraz (self .__ zivot> 0) je vlastne logická hodnota, môžeme vrátiť tú a kód sa značne zjednoduší:

@property
def nazivu(self):
    return self.__zivot > 0

Grafický život

Ako som sa už zmienil, metóda graficky_zivot () bude umožňovať vykresliť ukazovateľ života v grafickej podobe. Už vieme, že z hľadiska objektového návrhu nie je vhodné, aby metóda objektu priamo vypisovala do konzoly (ak nie je k výpisu objekt určený), preto si znaky uložíme do reťazca a ten vrátime pre neskoršie vypísanie. Ukážeme si kód metódy a následne podrobne popíšeme:

def graficky_zivot(self):
    celkem = 20
    pocet = int(self.__zivot / self.__max_zivot * celkem)
    if (pocet == 0 and self.nazivu):
        pocet = 1
    return "[{0}{1}]".format("#"*pocet, " "*(celkem-pocet))

Určíme si celkovú dĺžku ukazovateľa života do premennej spolu (napr. 20). Teraz v podstate nepotrebujeme nič iné, než trojčlenka. Ak max_zivot zodpovedá celkom dielikov, zivot bude zodpovedať pocet dielkam. Premenná pocet je počet dielikov aktuálneho zdravie.

Matematicky platí, že pocet = (zivot / maxZivot) * celkom. My ešte doplníme pretypovanie na celé číslo.

Mali by sme ošetriť prípad, kedy je život taký nízky, že nám vyjde na 0 dielikov, ale bojovník je stále nažive. V tom prípade vykreslíme 1 dielik, inak by to vyzeralo, že je už mŕtvy. Ďalej využijeme formátovanie a replikovanie.

Všetko si vyskúšame, prejdime na koniec súboru a vytvorme si bojovníka (a kocku, pretože tu musíme konstruktoru bojovníka odovzdať). Následne výpisy, či je nažive a jeho život graficky:

kostka = Kostka(10)
bojovnik = Bojovnik("Zalgoren", 100, 20, 10, kostka)
print("Bojovník: {0}".format(bojovnik)) #test __str__()
print("Naživu: {0}".format(bojovnik.nazivu)) #test naživu
print("Život: {0}".format(bojovnik.graficky_zivot())) #test graficky_zivot()
input()

A výsledok:

Stav bojovníka v Pythone - Objektovo orientované programovanie v Pythone

Boj

Dostávame sa k samotnému boju. Implementujeme metódy pre útok a obranu.

Obrana

Začnime obranou. Metóda bran_se () bude umožňovať brániť sa úderu, ktorého sila bude odovzdaná metóde ako parameter. Metódu si opäť ukážeme a potom popíšeme:

def bran_se(self, uder):
    zraneni = uder - (self.__obrana + self.__kostka.hod())
    if zraneni > 0:
        self.__zivot = self.__zivot - zraneni
        if self.__zivot < 0:
            self.__zivot = 0

Najprv spočítame skutočné zranenia a to tak, že z útoku nepriateľa odpočítame našu obranu zvýšenú o číslo, ktoré padlo na hracej kocke. Ak sme zranenia celej neodrazil (zranenie> 0), budeme znižovať náš život. Táto podmienka je dôležitá, keby sme zranenia odrazili a bolo napr. -2, bez podmienky by sa život zvýšil. Po znížení života skontrolujeme, či nie je v zápornej hodnote a prípadne ho dorovnáme na nulu.

Útok

Metóda Útočia () bude brať ako parameter inštanciu bojovníka, na ktorého sa útočí. To preto, aby sme na ňom mohli zavolať metódu bran_se (), ktorá na náš útok zareaguje a zmenší protivníkov život. Tu vidíme výhody referencií v Pythone, môžeme si inštancie jednoducho odovzdávať a volať na nich metódy, bez toho aby došlo k ich skopírovanie. Ako prvý vypočítame úder, podobne ako pri obrane, úder bude náš útok + hodnota z hracej kocky. Na súperovi následne zavoláme metódu bran_se () s hodnotou úderu:

def utoc(self, souper):
    uder = self.__utok + self.__kostka.hod()
    souper.bran_se(uder)

To by sme mali, poďme si skúsiť v našom ukážkovom programe zaútočiť a potom znova vykresliť život. Pre jednoduchosť nemusíme zakladať ďalšieho bojovníka, ale môžeme zaútočiť sami na seba:

kostka = Kostka(10)
bojovnik = Bojovnik("Zalgoren", 100, 20, 10, kostka)
print("Bojovník: {0}".format(bojovnik)) #test __str__()
print("Naživu: {0}".format(bojovnik.nazivu)) #test naživu
print("Život: {0}".format(bojovnik.graficky_zivot())) #test graficky_zivot()
bojovnik.utoc(bojovnik)
print("Život po útoku: {0}".format(bojovnik.graficky_zivot()))
input()
Stav bojovníka v Pythone - Objektovo orientované programovanie v Pythone

Zdá sa, že všetko funguje, ako má. Prejdime k poslednému bodu dnešného tutoriálu a to k správam.

Správy

Ako už bolo povedané, o útokoch a obrane budeme užívateľa informovať výpisom na konzolu. Výpis nebude vykonávať samotná trieda Bojovnik, tá bude len vracať správy ako textové reťazce. Jedna možnosť by bola pri volaní metód útokoch () a bran_se () vrátiť aj správu. Problém by však nastal v prípade, keď by sme chceli získať správu od metódy, ktorá už niečo vracia. To by nebolo moc pekné riešenie.

Poďme na vec univerzálnejšie, správu budeme ukladať do privátnej premennej sprava a urobíme metódy pre jej uloženie a vrátenie. Samozrejme by sme mohli urobiť premennú verejnú, ale nie je tu dôvod, prečo umožniť zvonku zápis do správy a tiež by skladanie zložitejšie správy vnútri triedy mohlo byť niekedy problematické.

Do metódy __init __ () teda pridáme:

self.__zprava = ""

Teraz si vytvoríme dve metódy. Privátne __nastav_zpravu (), ktorá berie ako parameter text správy a slúži na interné účely triedy, kde nastaví správu do privátnej premennej. Všimnite si, že súkromné metódy tiež začínajú s dvoma podtržníkmi.

def __nastav_zpravu(self, zprava):
    self.__zprava = zprava

Nič zložité. Podobne jednoduchá bude verejná metóda pre navrátenie správy:

def vrat_posledni_zpravu(self):
    return self.__zprava

O prácu so správami obohatíme naše metódy útočí () a bran_se (), teraz budú vyzerať takto:

def bran_se(self, uder):
    zraneni = uder - (self.__obrana + self.__kostka.hod())
    if zraneni > 0:
        zprava = "{0} utrpěl poškození {1} hp.".format(self.__jmeno, zraneni)
        self.__zivot = self.__zivot - zraneni
        if self.__zivot < 0:
            self.__zivot = 0
            zprava = zprava[:-1] + " a zemřel."
    else:
        zprava = "{0} odrazil útok.".format(self.__jmeno)
    self.__nastav_zpravu(zprava)

def utoc(self, souper):
    uder = self.__utok + self.__kostka.hod()
    zprava = "{0} útočí s úderem za {1} hp.".format(self.__jmeno, uder)
    self.__nastav_zpravu(zprava)
    souper.bran_se(uder)

Všetko si opäť vyskúšame, tentoraz už vytvoríme druhého bojovníka:

kostka = Kostka(10)
bojovnik = Bojovnik("Zalgoren", 100, 20, 10, kostka)
print("Život: {0}".format(bojovnik.graficky_zivot())) #test graficky_zivot()
#útok na našeho bojovníka
souper = Bojovnik("Shadow", 60, 18, 15, kostka)
souper.utoc(bojovnik)
print(souper.vrat_posledni_zpravu())
print(bojovnik.vrat_posledni_zpravu())
print("Život: {0}".format(bojovnik.graficky_zivot()))
input()
Stav bojovníka v Pythone - Objektovo orientované programovanie v Pythone

Máme kocku i bojovníka, teraz už chýba len aréna. Tú si vytvoríme hneď v nasledujúcej lekcii, Python - Aréna s bojovníkmi .


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 1043x (5.25 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python

 

Predchádzajúci článok
Kvíz - Úvod, konštruktory, atribúty a metódy v Pythone OOP
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Python - Aréna s bojovníkmi
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
1 hlasov
(^_^)
Aktivity