8. diel - Aréna s mágom (dedičnosť a polymorfizmus) vo Swift
V minulej lekcii, Dedičnosť a polymorfizmus vo Swift , sme si vysvetlili dedičnosť a polymorfizmus. Dnes máme sľúbené, že si ich vyskúšame v praxi. Bude to opäť na našej aréne, kde z bojovníka oddědíme mága. Tento Swift tutoriál už patrí k tým náročnejším a bude tomu tak aj u ďalších. Preto si priebežne precvičujte prácu s objektmi a tiež vymýšľajte nejaké svoje aplikácie, aby ste si zažili základné veci. To, že je tu prítomný celý online kurz neznamená, že ho celý naraz prečítate a pochopíte Snažte sa programovať priebežne.
Než začneme niečo písať, zhodneme sa na tom, čo by mal mág vedieť. Mág bude fungovať rovnako, ako bojovník. Okrem života bude mať však aj manu. Spočiatku bude mana plná. V prípade plnej many môže mág vykonať magický útok, ktorý bude mať pravdepodobne vyššie damage, ako útok normálne (ale samozrejme záleží na tom, ako si ho nastavíme). Tento útok manu vybije na0
. Každé kolo sa bude
mana zvyšovať o 10 a mág bude podnikať len bežný útok. Akonáhle sa mana
úplne doplní, opäť bude môcť magický útok použiť. Mana bude zobrazená
grafickým ukazovateľom, rovnako ako život.
Vytvoríme teda triedu Mag
v súbore
Bojovnik.swift
, zdedíme ju z Bojovnik
a dodáme ju
vlastnosti, ktoré chceme oproti bojovníkovi navyše. Bude teda vyzerať
takto:
class Mag: Bojovnik { private var mana : Double private var maxMana : Double private var magickyUtok : Int }
V mágovi nemáme zatiaľ prístup ku všetkým premenným, pretože sú v
bojovníkovi nastavené ako privátne. Musíme triedu Bojovnik
ľahko upraviť. Zmeníme modifikátory private
u vlastností na
fileprivate
. Budeme potrebovať len
kostka
a jmeno
, ale pokojne nastavíme ako
fileprivate
všetky vlastnosti charakteru, pretože sa v
budúcnosti môžu hodiť, keby sme sa rozhodli oddědit ďalšie typy
bojovníkov. Naopak vlastnosť zprava
nie je vhodné nastavovať
ako fileprivate
, pretože nesúvisí s bojovníkom, ale s nejakou
vnútornou logikou triedy. Trieda teda bude vyzerať nejako takto:
class Bojovnik { fileprivate var jmeno : String fileprivate var zivot : Double fileprivate var maxZivot : Double fileprivate var utok : Int fileprivate var obrana : Int fileprivate var kostka : Kostka private var zprava : String = "" // ...
Prejdime ku konstruktoru.
Viac konštruktor vo Swift
Nastala ideálnu príležitosť vysvetliť si, ako vo Swiftu funguje viac
konstruktoru, respektíve metód init()
. Swift rozlišuje tzv.
Designated a convenience konštruktory. Designated by sa dalo najlepšie
preložiť ako "označený" a je to vlastne primárnou / predvolený
konštruktor. Ak máme iba jeden init()
, tak je automaticky
designated.
Ak chceme mať v triede viac konstruktoru, aby sa dala jej inštancie
vytvoriť na základe rôznych parametrov, tak musíme mať tie ďalšie
označené slovíčkom convenience
, čo by sa dalo označiť ako
pohodlný. A tieto konštruktory musia cez self
volať designated
konštruktor. Nie je to nič zložité a môžeme si ukázať jednoduchý
prípad, ak by sme chceli nášho bojovníka vytvoriť bez parametrov. Vyzeralo
by to asi takto:
init(jmeno: String, zivot: Int, utok: Int, obrana: Int, kostka: Kostka) { self.jmeno = jmeno self.zivot = Double(zivot) self.maxZivot = self.zivot self.utok = utok self.obrana = obrana self.kostka = kostka } convenience init() { self.init(jmeno: "Standardní válečník", zivot: 100, utok: 20, obrana: 10, kostka: Kostka()) }
Teraz môžeme zadať parametre bojovníka, použiť prvý konštruktor, ale
aj napísať iba new Bojovnik()
, čím sa použije konštruktor
druhý. Ten pomocou volania designated konstruktoru nastaví predvolené
hodnoty.
Konštruktor potomka
Swift dedí konstruktory iba v špecifických prípadoch. Konštruktor bude
zdedený, ak novým vlastnostiam potomka nastavíme predvolené hodnoty (alebo
budú Optional
) a tým pádom nie je vyžadovaný konštruktor.
Rovnako tak nesmieme vytvoriť designated init()
metódu, aby sme
neprišli o zdedený konštruktor. Convenience konštruktory je možné
pridať.
V našom prípade mága bude lepšie vytvoriť vlastný konštruktor, pretože máme vlastnosti navyše, ktoré v ňom chceme nastavovať.
Definujeme si teda konštruktor v potomkovi, ktorý berie parametre potrebné pre vytvorenie bojovníka a niekoľko parametrov navyše pre mága.
V konštruktor potomkov je nutné vždy volať konštruktor predka. Je to z toho dôvodu, že bez volania konstruktoru nemusí byť inštancie správne inicializovaná. Konštruktor predka nevoláme iba v prípade, že žiadny nemá. Náš konštruktor musia mať samozrejme všetky parametre potrebné pre predka plus tie nové, čo má navyše potomok. Niektoré potom odovzdáme predkovi a niektoré si spracujeme sami. Konštruktor predka je nutné zavolať až nakoniec, inak Swift zobrazí chybu.
Vo Swift existuje kľúčové slovo super
,
ktoré je podobné nami už známemu self
. Na rozdiel od
self
, ktoré odkazuje na konkrétnu inštanciu triedy,
super
odkazuje na predka. My teda môžeme
zavolať konštruktor predka s danými parametrami a potom vykonať navyše
inicializáciu pre mága.
Konštruktor mága bude teda vyzerať takto:
init(jmeno: String, zivot: Int, utok: Int, obrana: Int, kostka: Kostka, mana: Int, magickyUtok: Int) { self.mana = Double(mana) self.maxMana = self.mana self.magickyUtok = magickyUtok super.init(jmeno: jmeno, zivot: zivot, utok: utok, obrana: obrana, kostka: kostka) }
Rovnako môžeme volať aj iný konštruktor v tej istej triede
(nie predka), len miesto super
použijeme self
.
Opäť sme si previedli manu interne na Double
, čoskoro
uvidíte prečo.
Presuňme sa teraz do main.swift
a druhého bojovníka (Shadow)
zmeňme na mága, napr. Takto:
let gandalf : Bojovnik = Mag(jmeno: "Gandalf", zivot: 60, utok: 15, obrana: 12, kostka: kostka, mana: 30, magickyUtok: 45)
Zmenu samozrejme musíme urobiť aj v riadku, kde bojovníka do arény
vkladáme. Všimnite si, že mága ukladáme do premennej typu
Bojovnik
. Nič nám v tom nebráni, pretože bojovník je jeho
predok. Rovnako tak si môžeme typ premennej zmeniť na Mag
. Keď
aplikáciu teraz spustíme, bude fungovať úplne rovnako, ako predtým. Mág
všetko dedí z bojovníka a zatiaľ teda funguje ako bojovník.
Polymorfizmus a prepisovanie metód
Bolo by výhodné, keby objekt Arena
mohol s mágom pracovať
rovnako ako s bojovníkom. My už vieme, že takémuto mechanizmu hovoríme
polymorfizmus. Aréna zavolá na objekte metódu
utoc()
so súperom v parametri. Nestará sa o to, či bude útok
vykonávať bojovník alebo mág, bude s nimi pracovať rovnako. U mága si teda
prepíšeme metódu utoc()
z predka. Prepíšeme
zdedenú metódu tak, aby útok pracoval s mannou, hlavička metódy však
zostane rovnaká.
Prepísanie metódy z predka vykonáme v potomkovi pomocou slovíčka
override
, ako si ukážeme nižšie.
Keď sme pri metódach, budeme ešte určite používať metódu
nastavZpravu()
, tá je však privátne. Označme ju ako
fileprivate
:
fileprivate func nastavZpravu(_ zprava: String)
Pri návrhu bojovníka sme samozrejme mali myslieť na to, že sa z neho bude
dediť a už označiť vhodné vlastnosti a metódy ako
fileprivate
.
Teraz sa vráťme do potomka a poďme prepísať metódu utoc()
.
Metódu normálne definujeme v Mag.swift
tak, ako sme zvyknutí.
Jej definíciu ale začneme slovom override
,
ktoré značí, že si sme vedomí toho, že sa metóda zdedila, ale prajeme si
zmeniť jej správanie.
override func utoc(souper: Bojovnik)
Správanie metódy utoc()
nebude nijako zložité. Podľa
hodnoty many buď vykonáme bežný útok alebo útok magický. Hodnotu many
potom buď zvýšime o 10 alebo naopak znížime na 0
v prípade
magického útoku.
override func utoc(souper: Bojovnik) { var uder = 0 // Mana není naplněna if mana < maxMana { mana += 10; if (mana > maxMana) { mana = maxMana } uder = utok + kostka.hod(); nastavZpravu("\(jmeno) útočí s úderem za \(uder) hp") } else { // Magický útok uder = magickyUtok + kostka.hod() nastavZpravu("\(jmeno) použil magii za \(uder) hp") mana = 0 } souper.branSe(uder: uder) }
Kód je asi zrozumiteľný. Všimnite si obmedzenia many na
maxMana
, môže sa nám totiž stať, že túto hodnotu presiahne,
keď ju zvyšujeme o 10. Keď sa nad kódom zamyslíme, tak útok vyššie v
podstate vykonáva pôvodnej metóda utoc()
. Iste by bolo
prínosné zavolať podobu metódy na predkovi namiesto toho, aby sme správanie
odpisovali. K tomu opäť použijeme super
:
{SWIFT} class Bojovnik: CustomStringConvertible { fileprivate var jmeno : String fileprivate var zivot : Double fileprivate var maxZivot : Double fileprivate var utok : Int fileprivate var obrana : Int fileprivate var kostka : Kostka private var zprava : String = "" init(jmeno: String, zivot: Int, utok: Int, obrana: Int, kostka: Kostka) { self.jmeno = jmeno self.zivot = Double(zivot) self.maxZivot = self.zivot self.utok = utok self.obrana = obrana self.kostka = kostka } convenience init() { self.init(jmeno: "Standardní válečník", zivot: 100, utok: 20, obrana: 10, kostka: Kostka()) } var description: String { return jmeno } func nazivu() -> Bool { return zivot > 0 } func grafickyZivot() -> String { var s = "[" let celkem : Double = 20 var pocet : Double = round((zivot / maxZivot) * celkem) if (pocet == 0) && (nazivu()) { pocet = 1 } for _ in 0..<Int(pocet) { s += "#" } s = s.padding(toLength: Int(celkem) + 1, withPad: " ", startingAt: 0) s += "]" return s } func utoc(souper: Bojovnik) { let uder = utok + kostka.hod() nastavZpravu("\(jmeno) útočí s úderem za \(uder) hp") souper.branSe(uder: uder) } func branSe(uder: Int) { let zraneni = Double(uder - (obrana + kostka.hod())) var zprava = "" if (zraneni > 0) { zivot -= zraneni zprava = "\(jmeno) utrpěl poškození \(Int(zraneni)) hp" if (zivot <= 0) { zivot = 0 } } else { zprava = "\(jmeno) odrazil útok" } nastavZpravu(zprava) } fileprivate func nastavZpravu(_ zprava: String) { self.zprava = zprava } func vratPosledniZpravu() -> String { return zprava } } class Mag: Bojovnik { private var mana : Double private var maxMana : Double private var magickyUtok : Int init(jmeno: String, zivot: Int, utok: Int, obrana: Int, kostka: Kostka, mana: Int, magickyUtok: Int) { self.mana = Double(mana) self.maxMana = self.mana self.magickyUtok = magickyUtok super.init(jmeno: jmeno, zivot: zivot, utok: utok, obrana: obrana, kostka: kostka) } override func utoc(souper: Bojovnik) { var uder = 0 // Mana není naplněna if mana < maxMana { mana += 10; if (mana > maxMana) { mana = maxMana } super.utoc(souper: souper) nastavZpravu("\(jmeno) útočí s úderem za \(uder) hp") } else { // Magický útok uder = magickyUtok + kostka.hod() nastavZpravu("\(jmeno) použil magii za \(uder) hp") mana = 0 } souper.branSe(uder: uder) } } {/SWIFT}
{SWIFT} class Arena { private var bojovnik1 : Bojovnik private var bojovnik2 : Bojovnik private var kostka : Kostka init(bojovnik1: Bojovnik, bojovnik2: Bojovnik, kostka: Kostka) { self.bojovnik1 = bojovnik1 self.bojovnik2 = bojovnik2 self.kostka = kostka } func vykresli() { print("\n \n \n \n \n \n \n \n") print("-------------- Aréna -------------- \n") print("Zdraví bojovníků: \n") print("\(bojovnik1) \(bojovnik1.grafickyZivot())") print("\(bojovnik2) \(bojovnik2.grafickyZivot())") } private func vypisZpravu(_ zprava: String) { print(zprava) sleep(1) } func zapas() { // původní pořadí var b1 = bojovnik1 var b2 = bojovnik2 print("Vítejte v aréně!") print("Dnes se utkají \(bojovnik1) s \(bojovnik2)! \n") // prohození bojovníků let zacinaBojovnik2 = kostka.hod() <= kostka.vratPocetSten() / 2 if (zacinaBojovnik2) { b1 = bojovnik2 b2 = bojovnik1 } print("Začínat bude bojovník \(b1)! \nZápas může začít...") _ = readLine() // cyklus s bojem while b1.nazivu() && b2.nazivu() { b1.utoc(souper: b2) vykresli() vypisZpravu(b1.vratPosledniZpravu()) // zpráva o útoku vypisZpravu(b2.vratPosledniZpravu()) // zpráva o obraně if (b2.nazivu()) { b2.utoc(souper: b1) vykresli() vypisZpravu(b2.vratPosledniZpravu()) // zpráva o útoku vypisZpravu(b1.vratPosledniZpravu()) // zpráva o obraně } print(" ") } } } {/SWIFT}
{SWIFT} // vytvoření objektů let kostka = Kostka(pocetSten: 10) let zalgoren = Bojovnik(jmeno: "Zalgoren", zivot: 100, utok: 20, obrana: 10, kostka: kostka) let gandalf : Bojovnik = Mag(jmeno: "Gandalf", zivot: 60, utok: 15, obrana: 12, kostka: kostka, mana: 30, magickyUtok: 45) let arena = Arena(bojovnik1: zalgoren, bojovnik2: gandalf, kostka: kostka) // zápas arena.zapas() {/SWIFT}
{SWIFT} class Kostka : CustomStringConvertible { var description: String { return "Kostka s \(pocetSten) stěnami" } private var pocetSten : Int init() { pocetSten = 6 } init(pocetSten: Int) { self.pocetSten = pocetSten } func vratPocetSten() -> Int { return pocetSten } func hod() -> Int { return Int(arc4random_uniform(UInt32(pocetSten))) + 1 } } {/SWIFT}
Opäť vidíme, ako môžeme znovupoužívat kód. S dedičnosťou je spojené naozaj mnoho techník, ako si ušetriť prácu. V našom prípade to ušetrí niekoľko riadkov, ale u väčšieho projektu by to mohlo mať obrovský význam.
Aplikácia teraz funguje tak, ako má.
-------------- Aréna -------------- Zdraví bojovníků: Zalgoren [############# ] Gandalf [################# ] Gandalf použil magii za 52 hp Zalgoren utrpěl poškození 36 hp
Aréna nás však neinformuje o mane mága, poďme to napraviť. Pridáme
mágovi verejnú metódu grafickaMana()
, ktorá bude obdobne ako u
života vracať String
s grafickým ukazovateľom many.
Aby sme nemuseli logiku so zložením ukazovatele písať dvakrát, upravíme
metódu grafickyZivot()
v Bojovnik.swift
. Pripomeňme
si, ako vyzerá:
func grafickyZivot() -> String { var s = "[" let celkem : Double = 20 var pocet : Double = round((zivot / maxZivot) * celkem) if (pocet == 0) && (nazivu()) { pocet = 1; } for _ in 0..<Int(pocet) { s += "#" } s = s.padding(toLength: Int(celkem) + 1, withPad: " ", startingAt: 0) s += "]" return s }
Vidíme, že nie je výnimkou premenných zivot
a
maxZivot
na živote nijako závislá. Metódu premenujeme na
grafickyUkazatel()
a dáme ju 2 parametre: aktuálnu hodnotu a
maximálnu hodnotu. Premenné zivot
a maxZivot
v tele
metódy potom nahradíme za aktualni
a maximalni
.
Modifikátor bude fileprivate
, aby sme metódu mohli v potomkovi
použiť:
fileprivate func grafickyUkazatel(aktualni: Double, maximalni: Double) -> String { var s = "[" let celkem : Double = 20 var pocet : Double = round((aktualni / maximalni) * celkem) if (pocet == 0) && (nazivu()) { pocet = 1; } for _ in 0..<Int(pocet) { s += "#" } s = s.padding(toLength: Int(celkem) + 1, withPad: " ", startingAt: 0) s += "]" return s }
Metódu grafickyZivot()
v triede Bojovnik
naimplementujeme znovu, bude nám v nej stačiť jediný riadok a to zavolanie
metódy grafickyUkazatel()
s príslušnými parametrami:
func grafickyZivot() -> String { return grafickyUkazatel(aktualni: zivot, maximalni: maxZivot) }
Určite som mohol v tutoriálu s bojovníkom urobiť metódu
grafickyUkazatel()
rovno. Chcel som však, aby sme si ukázali, ako
sa rieši prípady, keď potrebujeme vykonať podobnú funkčnosť viackrát. S
takouto parametrizáciou sa v praxi budete stretávať často, pretože nikdy
presne nevieme, čo budeme v budúcnosti od nášho programu požadovať.
Teraz môžeme vykresľovať ukazovateľ tak, ako sa nám to hodí. Presuňme
sa do triedy Mag
a naimplementujme metódu
grafickaMana()
:
func grafickaMana() -> String { return grafickyUkazatel(aktualni: mana, maximalni: maxMana) }
Jednoduché, že? Teraz je mág hotový, zostáva len naučiť arénu
zobrazovať manu v prípade, že je bojovník mág. Presuňme sa teda do
Arena.swift
.
Rozpoznanie typu objektu
Keďže sa nám teraz vykreslenie bojovníka skomplikovalo, urobíme si na
neho samostatnú metódu vypisBojovnika()
, jej parametrom bude
daná inštancie bojovníka:
func vypisBojovnika(_ b: Bojovnik) { print(b) print("Život:", terminator: " ") print(b.grafickyZivot()) }
Teraz poďme reagovať na to, či je bojovník mág. Minule sme si povedali,
že k tomu slúži operátor is
:
func vypisBojovnika(_ b: Bojovnik) { print(b) print("Život:", terminator: " ") print(b.grafickyZivot()) if b is Mag { print("Mana:", terminator: " ") print((b as! Mag).grafickaMana()) } }
Bojovníka sme museli na mága pretypovať pomocou operátora
as
, aby sme sa k metóde grafickaMana()
dostali.
Samotný Bojovnik
ju totiž nemá. Zas tu máme výkričník známy
z Optional
. Funguje tu veľmi podobne. Keby premenná
b
nebola na pozadí typu Mag
, tak program spadne. My
sa ale najskôr pýtame pomocou is
, či Mag
je a až
potom vykonáme vynútené pretypovanie. Mohli by sme použiť ?
,
Ktorý by vrátil Optional
a my mohli výsledok pretypovania
spracovať bezpečne. Tu to ale nie je nutné a ani vhodné.
To by sme mali, vypisBojovnika()
budeme volať v metóde
vykresli()
, ktorá bude vyzerať takto:
{SWIFT} class Arena { private var bojovnik1 : Bojovnik private var bojovnik2 : Bojovnik private var kostka : Kostka init(bojovnik1: Bojovnik, bojovnik2: Bojovnik, kostka: Kostka) { self.bojovnik1 = bojovnik1 self.bojovnik2 = bojovnik2 self.kostka = kostka } func vykresli() { print("\n \n \n \n \n \n \n \n") print("-------------- Aréna -------------- \n") print("Zdraví bojovníků: \n") vypisBojovnika(bojovnik1) print(" ") vypisBojovnika(bojovnik2) } private func vypisZpravu(_ zprava: String) { print(zprava) sleep(1) } func zapas() { // původní pořadí var b1 = bojovnik1 var b2 = bojovnik2 print("Vítejte v aréně!") print("Dnes se utkají \(bojovnik1) s \(bojovnik2)! \n") // prohození bojovníků let zacinaBojovnik2 = kostka.hod() <= kostka.vratPocetSten() / 2 if (zacinaBojovnik2) { b1 = bojovnik2 b2 = bojovnik1 } print("Začínat bude bojovník \(b1)! \nZápas může začít...") _ = readLine() // cyklus s bojem while b1.nazivu() && b2.nazivu() { b1.utoc(souper: b2) vykresli() vypisZpravu(b1.vratPosledniZpravu()) // zpráva o útoku vypisZpravu(b2.vratPosledniZpravu()) // zpráva o obraně if (b2.nazivu()) { b2.utoc(souper: b1) vykresli() vypisZpravu(b2.vratPosledniZpravu()) // zpráva o útoku vypisZpravu(b1.vratPosledniZpravu()) // zpráva o obraně } print(" ") } } func vypisBojovnika(_ b: Bojovnik) { print(b) print("Život:", terminator: " ") print(b.grafickyZivot()) if b is Mag { print("Mana:", terminator: " ") print((b as! Mag).grafickaMana()) } } } {/SWIFT}
{SWIFT} class Bojovnik: CustomStringConvertible { fileprivate var jmeno : String fileprivate var zivot : Double fileprivate var maxZivot : Double fileprivate var utok : Int fileprivate var obrana : Int fileprivate var kostka : Kostka private var zprava : String = "" init(jmeno: String, zivot: Int, utok: Int, obrana: Int, kostka: Kostka) { self.jmeno = jmeno self.zivot = Double(zivot) self.maxZivot = self.zivot self.utok = utok self.obrana = obrana self.kostka = kostka } convenience init() { self.init(jmeno: "Standardní válečník", zivot: 100, utok: 20, obrana: 10, kostka: Kostka()) } var description: String { return jmeno } func nazivu() -> Bool { return zivot > 0 } fileprivate func grafickyUkazatel(aktualni: Double, maximalni: Double) -> String { var s = "[" let celkem : Double = 20 var pocet : Double = round((aktualni / maximalni) * celkem) if (pocet == 0) && (nazivu()) { pocet = 1; } for _ in 0..<Int(pocet) { s += "#" } s = s.padding(toLength: Int(celkem) + 1, withPad: " ", startingAt: 0) s += "]" return s } func grafickyZivot() -> String { return grafickyUkazatel(aktualni: zivot, maximalni: maxZivot) } func utoc(souper: Bojovnik) { let uder = utok + kostka.hod() nastavZpravu("\(jmeno) útočí s úderem za \(uder) hp") souper.branSe(uder: uder) } func branSe(uder: Int) { let zraneni = Double(uder - (obrana + kostka.hod())) var zprava = "" if (zraneni > 0) { zivot -= zraneni zprava = "\(jmeno) utrpěl poškození \(Int(zraneni)) hp" if (zivot <= 0) { zivot = 0 } } else { zprava = "\(jmeno) odrazil útok" } nastavZpravu(zprava) } fileprivate func nastavZpravu(_ zprava: String) { self.zprava = zprava } func vratPosledniZpravu() -> String { return zprava } } class Mag: Bojovnik { private var mana : Double private var maxMana : Double private var magickyUtok : Int init(jmeno: String, zivot: Int, utok: Int, obrana: Int, kostka: Kostka, mana: Int, magickyUtok: Int) { self.mana = Double(mana) self.maxMana = self.mana self.magickyUtok = magickyUtok super.init(jmeno: jmeno, zivot: zivot, utok: utok, obrana: obrana, kostka: kostka) } override func utoc(souper: Bojovnik) { var uder = 0 // Mana není naplněna if mana < maxMana { mana += 10; if (mana > maxMana) { mana = maxMana } super.utoc(souper: souper) nastavZpravu("\(jmeno) útočí s úderem za \(uder) hp") } else { // Magický útok uder = magickyUtok + kostka.hod() nastavZpravu("\(jmeno) použil magii za \(uder) hp") mana = 0 } souper.branSe(uder: uder) } func grafickaMana() -> String { return grafickyUkazatel(aktualni: mana, maximalni: maxMana) } } {/SWIFT}
{SWIFT} // vytvoření objektů let kostka = Kostka(pocetSten: 10) let zalgoren = Bojovnik(jmeno: "Zalgoren", zivot: 100, utok: 20, obrana: 10, kostka: kostka) let gandalf : Bojovnik = Mag(jmeno: "Gandalf", zivot: 60, utok: 15, obrana: 12, kostka: kostka, mana: 30, magickyUtok: 45) let arena = Arena(bojovnik1: zalgoren, bojovnik2: gandalf, kostka: kostka) // zápas arena.zapas() {/SWIFT}
{SWIFT} class Kostka : CustomStringConvertible { var description: String { return "Kostka s \(pocetSten) stěnami" } private var pocetSten : Int init() { pocetSten = 6 } init(pocetSten: Int) { self.pocetSten = pocetSten } func vratPocetSten() -> Int { return pocetSten } func hod() -> Int { return Int(arc4random_uniform(UInt32(pocetSten))) + 1 } } {/SWIFT}
Hotovo
-------------- Aréna -------------- Zdraví bojovníků: Zalgoren Život: [########## ] Gandalf Život: [##### ] Mana: [############# ] Zalgoren útočí s úderem za 28 hp
Ak ste niečomu nerozumeli, skúste si článok prečítať viackrát alebo pomalšie, sú to dôležité praktiky. V budúcej lekcii, Riešené úlohy k 5.-8. lekciu OOP vo Swift , si vysvetlíme pojem statika.
V nasledujúcom cvičení, Riešené úlohy k 5.-8. lekciu OOP vo Swift, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkamiStiahnuté 8x (26.19 kB)