objektovo-orientované programovanie: prípadová štúdia pre...

117
Ján Juhár, Jana Št’astná, Miroslav Biˇ nas Objektovo-orientované programovanie: Prípadová štúdia pre cviˇ cenia EDÍCIA 2018 Technická Univerzita v Košiciach, 2019

Upload: others

Post on 19-Nov-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

Ján Juhár, Jana Št’astná, Miroslav Binas

Objektovo-orientovanéprogramovanie:Prípadová štúdiapre cvicenia

EDÍCIA 2018

Technická Univerzita v Košiciach, 2019

Page 2: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE :

PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Edícia 2018

Copyright © 2019 Ján Juhár, Jana Št’astná, Miroslav Binas

Technická Univerzita v Košiciach, 2019

Prvé vydanie, náklad 50 ks, 108 strán

ISBN 978-80-553-3369-4

Page 3: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

ObsahÚvod 1

I Not Too Short Introduction to OOP 3

II Red Alert: Reactor Overheat! 7

III Powering Devices 19

IV And... Action! 27

V Let’s Have an Agreement 37

VI I knew you’d come (Ripley) 51

VII Usable Items 63

VIII Mission Impossible 77

IX Intricate Devices of Life and Death 93

Page 4: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav
Page 5: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

Zoznam obrázkov

II.1 Nastavenie importu Gradle projektu v prostredí IntelliJ IDEA8

II.2 Prvé spustenie projektu pomocou nástroja Gradle 9

II.3 Východzia podoba levelu 9

II.4 Diagram tried, ktorý vyjadruje vzt’ah triedy Reactor s triedouAbstractActor. 10

II.5 Snímky sprite-u hlavnej postavy hry Jet Set Willy idúcej vpravo11

II.6 Výsledná animácia vytvorená postupným vykresl’ovanímobrázkov animácie 11

II.7 Animácia reactor_on.png 12

II.8 Plne funkcný reaktor 13

II.9 Animácia computer.png 13

II.10 Závislost’ zvyšovania poškodenia reaktora pri raste jehoteploty 14

II.11 Animácia reactor_hot.png 15

II.12 Animácia reactor_broken.png 15

II.13 Pokazený (prehriaty) reaktor 16

III.1 Diagram tried, ktorý vyjadruje vzt’ah tried Hammer a Ab-stractActor. 19

III.2 Animácia hammer.png 20

III.3 Diagram tried, ktorý vyjadruje vzt’ah tried Reactor a Ham-mer. 20

III.4 Animácia reactor.png 21

III.5 Diagram tried, ktorý vyjadruje vzt’ah tried Reactor a Con-troller. 22

Page 6: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

vi

III.6 Animácia switch.png 22

III.7 Štyri bloky reaktorov ovládané štyrmi vypínacmi. 23

III.8 Diagram tried, ktorý vyjadruje vzt’ah tried Light, Reac-tor a AbstractActor. 23

III.9 Animácia light_on.png (rozmery sprite-u: 16x16) 24

III.10 Animácia light_off.png (rozmery sprite-u: 16x16) 24

III.11 Každý reaktor napája jedno svetlo 25

III.12 Animácia extinguisher.png 26

III.13 Animácia reactor_extinguished.png 26

IV.1 Abstraktná trieda BreakableTool reprezentujúca poškoditel’nýnástroj. 27

IV.2 Vzt’ahy medzi aktérom, scénou a akciou. 29

IV.3 Vzt’ah tried Reactor a Cooler. 31

IV.4 Trieda Cooler. 31

IV.5 Animácia fan.png 31

IV.6 Pracovnú teplotu reaktora práve zabezpecujú dva chladicesúcasne. 33

IV.7 Dedicná línia triedy DefectiveLight 33

IV.8 okazené svetlo rozpoznáte od dobrého svetla na základejeho cinnosti. 34

IV.9 Animácia heli.png 35

V.1 MapMarker objekty v mape scény. 39

V.2 Vzt’ah tried k rozhraniu Switchable. 42

V.3 Reaktor zapnutý pomocou PowerSwitch-a. 43

V.4 Reaktor, svetlo a inteligentné chladice ovládané pomocouPowerSwitch-ov. 44

V.5 Vzt’ah tried k rozhraniu EnergyConsumer 44

V.6 Reaktorom napájaný pocítac 46

V.7 Animácia wrench.png 48

V.8 Animácia bomb.png 48

Page 7: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

vii

V.9 Animácia bomb_activated.png 48

V.10 Animácia small_explosion.png 48

V.11 Animácia lift.png 49

VI.1 Trieda Ripley implementujúca rozhranie Actor 55

VI.2 Animácia player.png 55

VI.3 Ripleyová nervózne prešl’apujúca na mieste. 56

VI.4 Implementácia pohybu pre aktérov. 56

VI.5 Controller pre ovládanie pohybu aktérov. 59

VII.1 Triedy Energy a Ammo implementujúce rozhranie Usable.63

VII.2 Animácia energy.png 64

VII.3 Ripleyová a lekárnicka. 66

VII.4 Sprite ammo.png (rozmery spritu: 16x16). 67

VII.5 Trieda Backpack implementujúca rozhranie ActorCon-tainer a rozhranie Keeper reprezentujúce aktérov s kon-tajnerom. 67

VII.6 Ripleyová vybavená batohom. 71

VII.7 Triedy akcií na prácu s kontajnermi aktérov. 71

VIII.1 Ripleyová nachádzajúca sa v reálnom svete zatial’ prechádzaaj cez steny. 80

VIII.2 Mapa scény so zobrazenou vrstvou walls v editore Tiled.80

VIII.3 Dvere, zamknuté dvere a prístupová karta na odomykanie.81

VIII.4 Animácia vertikálnych dverí vdoor.png 82

VIII.5 Dlaždice mapy s vyznacenou dlaždicou so súradnicami mriežky[3, 5] 82

VIII.6 Ripleyová stojí pred dverami, ktoré ešte nedokáže otvorit’.83

VIII.7 Animácia key.png 87

Page 8: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

viii

VIII.8 Ripleyová s prístupovou kartou v batohu prechádza odomknutýmidverami. 87

VIII.9 Diagram tried znázornujúci postavenie triedy Locker aVentilator 88

VIII.10 Animácia locker.png 88

VIII.11 Animácia ventilator.png 88

VIII.12 Ripleyová v zamorenom priestore. 90

VIII.13 Animácia umierajúcej Ripleyovej player_die.png 91

IX.1 Trieda Alien a jej vzt’ahy k existujúcim triedam a rozhra-niam. 94

IX.2 Animácia alien.png 94

IX.3 Ripleyová je živým aktérom. 95

IX.4 Trieda Alien 99

IX.5 Animácia mother.png 100

IX.6 Na palube sa nachádza príliš vel’a votrelcov 100

IX.7 Ripleyová získava zbran 101

IX.8 Animácia bullet.png 102

IX.9 Správanie aktérov 105

IX.10 Animácia vertikálnych dverí vdoor.png 105

IX.11 Animácia horizontálnych dverí hdoor.png 105

Page 9: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

ÚvodObjektovo-orientované programovanie (OOP) je jedným z povinnýchpredmetov bakalárskeho študijného programu Informatika na Katedrepocítacov a informatiky, FEI, TUKE. Táto kniha popisuje prípadovúštúdiu - súbor scenárov pre postupné riešenie komplexného projektuv rámci cvicení z predmetu OOP. Neobsahuje tradicné ucebné texty steóriou objektového programovania, ale slúži ako sprievodca jednouz ciest pre praktické použitie študentom osvojenej teórie, ci už zprednášok predmetu OOP alebo odbornej literatúry.

Prípadová štúdia je postavená na princípe výucby prostredníctvomhier, ktorý je vo svete známy ako game-based learning. Jadro tohtoprincípu nie je konštruktom technologickej éry, plnej pocítacovýchhier, ako by sa mohlo na prvý pohl’ad zdat’. Siaha do doby dávnopred vznikom osobných pocítacov, do cias Jána Amosa Komenského,ktorý sa zaoberal inováciami v pedagogike. V jeho casto spomínanejknihe Škola hrou 1 z roku 1651 sa zaoberal metódou, ktorá by žiakom 1 Názov Komenského spisu Škola

hrou je casto mylne používaný akoargument pre vytvorenie "hravého"prostredia na školách, alebo s výk-ladom, že vzdelanie má byt’ "hrou".Komenský však nic také svojim dielomnezamýšl’al a tieto interpretácie sú namíle d’aleko od skutocného obsahuknihy Škola hrou. Zaujímavým spô-sobom o tom pojednáva príspevokŠkola hrou, nebo hraní si ve škole? JaromírKopecký o Komenského spisu Škola hrou(https://www.ascestinaru.cz/skola-hrou-nebo-hrani-si-ve-skole-jaromir-kopecky-o-komenskeho-spisu-skola-hrou/).

pomohla naucit’ sa latinský jazyk. Dosiahol to prostredníctvomscénického vyobrazenia ucebnice latinciny Janua linguarum, ktorejtémy sú "predvedené l’udským zmyslom v živej cinnosti". Obdobne,prípadová štúdia pre cvicenia z predmetu OOP využíva grafiku adynamiku jednoduchej pocítacovej hry na vyobrazenie dôležitýchprincípov objektovo-orientovaného programovania.

Pri programovaní hry v postupných fázach môžu študenti jednodu-cho pozorovat’ a skúmat’ správanie svojho programu prostred-níctvom jeho aktérov – herných postáv, predmetov, alebo interakcious prostredím, v ktorom sa hra odohráva. Takto majú možnost’ získat’rýchlu vizuálnu spätnú väzbu, overit’ si správnost’ svojej implementá-cie a teda aj úroven porozumenia preberaných tém.

Riešenie ucelenej prípadovej štúdie umožnuje vyskúšat’ si viaceréfázy vývojového cyklu softvéru – nie len jednorázovo napísat’ zdro-jový kód s riešením úlohy, ale s odstupom casu sa vrátit’ k prvotnémuriešeniu, d’alej ho rozvinút’, vylepšit’, prepojit’ s novými cast’amiprogramu a získat’ skúsenosti na minulých chybách. Pri rozširovanífunkcionality vzniká možnost’ podrobit’ svoje pôvodné myšlienkovépochody analýze, overit’ si aplikovatel’nost’ prvotného nápadu nariešenie d’alších problémov, ktoré prirodzene vyvstanú pri doplnanífunkcionality programu. Študenti svoj zdrojový kód iteratívne po-drobia overovaniu, pribúdajúce skúsenosti im pomôžu identifikovat’

Page 10: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

2

predošlé nedostatky vo vlastnej implementácii a naviazat’ získanéporozumenie do jedného celku. V scenároch cvicení sa snažíme štu-dentov postupne naviest’ na riešenie problémov v súvislosti s d’alšímiproblémami, nie jedného problému osamotene, ked’že pre prax sipotrebujú vybudovat’ vnímanie problémov v ich širšom kontexte.

Kniha je clenená na 9 kapitol a každá z nich obsahuje jeden scenárprípadovej štúdie a teda nápln jedného študijného týždna. Kapi-tola zacína sekciou s názvom Motivácia, ktorá dokresl’uje "príbeh" –tému prípadovej štúdie, a nacrtáva problémy daného scenára. Sek-cia Ciele uvádza zameranie kapitoly z hl’adiska pojmov a princípovOOP. Nasledujúci obsah kapitoly je clenený na císlované sekcie zvanéKrok, v rámci ktorých je uvedený krátky sumár kroku a riešením ještudent sprevádzaný v císlovaných podsekciách s názvom Úloha. Zasúborom krokov a ich úloh, ktoré vedú k realizácii hlavnej funkcional-ity daného scenára štúdie, môžu nasledovat’ ešte Doplnujúce úlohy.Spravidla nie sú nevyhnutné pre daný scenár, no v neskoršíchscenároch môže byt’ funkcionalita z týchto úloh kl’úcová pre pokraco-vanie implementácie. Odporúcame preto po dokoncení hlavných úlohkapitoly vypracovat’ aj doplnujúce úlohy. V závere kapitoly môžu byt’uvedené Doplnujúce zdroje, ktoré sú užitocné pre vypracovanie úloh asplnenie krokov danej kapitoly.

Popri hlavnom texte je vyhradený priestor pri okraji strany naužitocné poznámky, referencie na použité zdroje, menšie obrázky ainý zaujímavý materiál. V elektronickej verzii knihy sú URL odkazyklikatel’né, ciže po kliknutí na ne sa daná stránka otvorí vo webovomprehliadaci.

Doplnkový materál ku knihe je k dispozícii online na adrese http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018.

Page 11: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INot Too Short Introduction to OOPZoznámte sa s objektovým programovaním hraním hry Alien Breed

MOTIVÁCIA

Na tomto cvicení sa budete hrat’. A popri tom hraní sa budete ucit’.Ciel’om cvicenia je úspešne prejst’ pripravenú hru AlienBreed a popri tom sa naucit’ niekol’ko základných

vlastností objektového programovania. Okrem toho, že sa nieco naucíte, osvojíte si aj princíp hry, ktorá budepredstavovat’ vaše zadanie z predmetu.

C IELE

1. Osvojit’ si pravidlá hry AlienBreed.

2. Porozumiet’ objektom a triedam pomocou hrania hry AlienBreed.

3. Oboznámit’ sa s diagramom tried.

4. Oboznámit’ sa so zapuzdrením údajov.

Krok 1: Let’s rock!

Vašou úlohou je hrat’ a vyhrat’ hru AlienBreed. Hrací cas, za ktorý AlienBreed je séria 2D hier s pohl’adomzhora, ktorá je tematicky zasadenádo prostredia inšpirovaného filmomAlien. Viac o hre je na stránke Wikipédiehttps://en.wikipedia.org/wiki/Alien_Breed_(video_game)

máte túto úlohu stihnút’, je 45 minút. Nezabudnite, že hra je vzdelá-vacia a nebude teda záležat’ iba na tom, kto prvý postriel’a všetkýchvotrelcov! Vel’a št’astia, hrác!

Úloha 1.1

Z adresy http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/alienbreed-intro.jar si stiahnite hru AlienBreed.

Úloha 1.2

Spustite hru a d’alej pokracujte podl’a pokynov na obrazovke.

Page 12: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

4 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Ak používate OS Linux, dvojklik pre spustenie vám pravde-podobne stacit’ nebude. Pre spustenie si najprv spustite príkazovýriadok (terminál), presunte sa do adresára, do ktorého ste hru stiahli, azadajte príkaz:

java -jar alienbreed-intro.jar

V prípade, že sa vám hra nespustí, s najväcšou pravdepodob-nost’ou nemáte nainštalovanú Javu (JRE). Preto si ju pre svoj systémnainštalujte.

Skratka JRE znamená Java RuntimeEnvironment. Predstavuje prostrediepotrebné pre spustenie aplikáciínapísaných v jazyku Java. Na vývojaplikácií v tomto jazyku budete potrebo-vat’ JDK - Java Development Kit, ktorý užzahrna aj JRE. Preto rovno odporúcameinštalovat’ JDK, pokial’ pracujete napocítaci, ktorý budete používat’ nad’alejaj pri riešení d’alších úloh

Krok 2: Ready, steady, go!

Tento predmet ale nebude len o hraní. Aby sme mohli nabudúceplynulo odštartovat’, pripravte si na svojich pocítacoch požadovanésoftvérové vybavenie.

Úloha 2.1

Pokial’ nemáte, nainštalujte si SDK jazyka Java (tiež známe ako JavaDevelopment Kit, skrátene JDK) pre váš operacný systém, minimálnevo verzii 10. Vývojový cyklus platformy Java je v

súcasnosti omnoho rýchlejší, ako tomubolo kedysi. Je možné, že v case, kedycítate túto knihu, budú dostupné ajnovšie verzie než 10. Tie by mali byt’plne kompatibilné, takže si môžetenainštalovat’ tú najnovšiu podporovanúverziu.

Java SDK môžete stiahnut’ zo stránky https://www.oracle.

com/technetwork/java/javase/downloads/index.html,alebo využit’ balíckovací systém vášho operacného systému. Uistite saale, že inštalujete naozaj JDK minimálne vo verzii 10!

Úloha 2.2

Nainštalujte si vývojové prostredie IntelliJ IDEA. Dostupné je nastránke https://www.jetbrains.com/idea/download/.

Na tomto predmete nám bude stacit’ open source verzia prostre-dia IntelliJ IDEA Community Edition. Ako študenti si však môžete vprípade záujmu zadarmo, no výlucne na študijné úcely, stiahnut’ aj Podmienky využívania študentskej

licencie sú dostupné na stránke https://www.jetbrains.com/student/license_educational.html.Oboznámte sa s nimi skôr, než licen-ciu zacnete využívat’.

inak platenú verziu IntelliJ IDEA Ultimate, po vytvorení JetBrains úctupoužitím vašej univerzitnej emailovej adresy.

Prehl’ad o študentskej licencii a odkazna registracný formulár je na adresehttps://www.jetbrains.com/student/.

Ak ste už mali prostredie IntelliJ IDEA nainštalované, uistite sa, žemáte minimálne verziu 2018.2. Ak máte staršiu, aktualizujte si ju.

Doplnujúce zdroje• Hra AlienBreed na Wikipédii

https://en.wikipedia.org/wiki/Alien_Breed_(video_game)

Page 13: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

NOT TOO SHORT INTRODUCTION TO OOP 5

• Java Tutoriál: Objekthttp://download.oracle.com/javase/tutorial/java/concepts/object.html

• Java Tutoriál: Triedahttp://download.oracle.com/javase/tutorial/java/concepts/class.html

• Java Tutoriál: Dedicnost’http://docs.oracle.com/javase/tutorial/java/concepts/inheritance.html

Page 14: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav
Page 15: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

IIRed Alert: Reactor Overheat!Reaktor, v ktorom nadmerne stúpne teplota, vie narobit’ riadnu paseku.

MOTIVÁCIA

Vitaj vo výcvikovom stredisku, kadet, kde z teba pocas niekol’ko-týždnového tréningu spravíme ozajstnéhochlapa (rozumej objektového programátora)! O formu a podobu tvojho výcviku sa bude starat’ náš taktický astrategický tím, ktorý má s výcvikom kadetov tvojho formátu dlhorocné skúsenosti a rozhodne t’a nenechávydýchnut’. Tvoj výcvik je totiž jeho prioritou.

Dnes to bude len zahrievacie kolo, v ktorom uvidíme, co si zac, co v tebe je a co od teba teda môžemeocakávat’. Aj ked’ sa jedná len o zahrievacie kolo, mnoho kadetov trhá tím a zostáva pri plnení dnešnej misieešte niekol’ko týždnov. Veríme, že ty partiu trhat’ nebudeš!

Z operacného strediska zdraví Manager.

C IELE

1. Naucit’ sa pracovat’ s projektom vo vývojovom prostredí.

2. Naucit’ sa vytvárat’ vlastné triedy, ich konštruktory a metódy.

3. Naucit’ sa pret’ažit’ implementáciu metódy pre rôzne typy parametrov.

4. Naucit’ sa reprezentovat’ stav objektu clenskými premennými(zapuzdrenie údajov).

5. Naucit’ sa riadit’ viditel’nost’ clenských premenných a metód.

6. Naucit’ sa vytvárat’ inštancie objektov z tried.

Krok 1: Warming up

Kadet! Aby tvoj výcvik mohol zacat’, musíš si najprv pripravit’ svojeprostredie. Stiahneš si kostru projektu, v ktorom budeš pracovat’.

Predpokladom pre prácu s projektomje nainštalovaný Java Development Kit(JDK) minimálne verzie 10. Môžete hostiahnut’ zo stránky https://www.oracle.com/technetwork/java/javase/downloads/index.html,alebo využit’ balíckovací systém vášhooperacného systému.

Page 16: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

8 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 1.1

Stiahnite si balícek s projektom z adresy http://oop-kniha.

pages.kpi.fei.tuke.sk/edicia-2018/download/project-ellen.

zip, rozbal’te ho a otvorte vo vývojovom prostredí IntelliJ IDEA.Pri otváraní projektu použite možnost’ Open z uvítacej obrazovky

prostredia, alebo z menu File. Zvol’te adresár, kde máte rozbalenýstiahnutý projekt (daný adresár obsahuje súbor build.gradle.kts).A ked’že v projekte používame zostavovací nástroj Gradle1, zobrazí

1 Gradle umožnuje jednoduchýmspôsobom konfigurovat’ zostavenie ajrozsiahlejšieho projektu, využívajúcehorôzne d’alšie knižnice alebo softvérovérámce. Tiež zjednodušuje spravovaniezávislostí projektu. Viac o nástrojiGradle je na oficiálnej stránke https://gradle.org.

sa následne okno, v ktorom je potrebné nastavit’ vytvorenie IDEAprojektu (Obr. II.1).

Obr. II.1: Nastavenie importu Gradleprojektu v prostredí IntelliJ IDEA

Skontrolujte, že máte nastavenia tak, ako sú na uvedenom obrázkuokna. Ak pre nastavenie Gradle JVM nemáte položku pre Javu 10,kliknite na tlacidlo ... a zvol’te adresár, kde máte nainštalovaný JDK10. Použitie IntelliJ IDEA nie je nevyhnutné

pre prácu s projektom, ten bude funkcnýv l’ubovol’nom IDE s podporou zostavo-vacieho nástroja Gradle. V rámci týchtomateriálov však budeme predpokladat’použitie práve prostredia IntelliJ IDEA.

Po kliknutí na tlacidlo OK sa otvorí projekt a spustí sa konfigurácianástroja Gradle a synchronizácia závislostí projektu (knižníc, ktorédaný projekt používa). Tento proces môže trvat’ aj niekol’ko minút,ked’že je potrebné stiahnut’ Gradle a všetky závislosti projektu. Processa ukoncí indexovaním stiahnutých knižníc, o ktorom vás budeprostredie informovat’ v spodnom stavovom riadku.

Page 17: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

RED ALERT: REACTOR OVERHEAT ! 9

Úloha 1.2

Overte funkcnost’ projektu jeho spustením.Pre prvé spustenie projektu je potrebné otvorit’ nástrojové okno pre

Gradle, vyhl’adat’ úlohu (task) run v skupine application (vid’ Obr. II.2) Nástrojové okno Gradle má tlacidlovpravo hore na vertikálnej lište pozdlžokraja okna prostredia. Ak túto lištunevidíte, zapnite ju v menu View → ToolButtons.

a spustit’ ju (napr. dvojklikom).

Obr. II.2: Prvé spustenie projektupomocou nástroja Gradle

Prvým manuálnym spustením akcie runsa v prostredí IntelliJ IDEA vytvorí tzv.run konfigurácia s názvom "project-ellen[run]", ktorú nájdete v prostredí nahorizontálnej lište vpravo hore. Pokial’je táto konfigurácia zobrazená, d’alšiespustenia sú možné pomocou tlacidlazelenej šípky vedl’a, alebo pomocouklávesovej skratky Shift+F10.

Ak je všetko v poriadku, po kompilácii projektu sa vám zobrazí vý-chodzia mapa základného levelu (Obr. II.3) spolu s oknom inšpektora.

Obr. II.3: Východzia podoba levelu hry

Krok 2: Reactor Class

Tvojou úlohou je vytvorit’ triedu, ktorá bude reprezentovat’ reaktor vprostredí hry Alien Breed. Stav reaktora bude reprezentovaný aktuál-

Page 18: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

10 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

nou teplotou jeho jadra, celkovým poškodením reaktora a animáciou,ktorá aktuálny stav vizualizuje.

<<abstract>>AbstractActor Reactor

Obr. II.4: Diagram tried, ktorý vy-jadruje vzt’ah triedy Reactor s triedouAbstractActor.

Úloha 2.1

Vytvorte v projekte Java balík sk.tuke.kpi.oop.game.Ked’že projekt používa nástroj Gradle, je potrebné dodržat’ jeho

konvenciu na umiestnovanie Java zdrojových súborov2, a preto je 2 Konvencia je popísaná na stránkehttps://docs.gradle.org/current/userguide/java_plugin.html#sec:java_project_layout

potrebné vytvorit’ tento balík v adresári src/main/java.

Úloha 2.2

V balíku sk.tuke.kpi.oop.game vytvorte triedu Reactor, ktorábude potomkom triedy AbstractActor.

Trieda AbstractActor, ktorú použijete ako rodicovskú triedunovej triedy Reactor, predstavuje všeobecného aktéra hry. Je súcast’ouknižnice GameLib, ktorá je definovaná medzi závislost’ami vášhoprojektu. Nie je preto potrebné ju vytvárat’ samostatne! Stací ju impor-tovat’ do súboru vytvoreného pre triedu Reactor. V tomto vám aledokáže pomôct’ samotné vývojové prostredie.

Pri zápise názvu rodicovskej triedyAbstractActor vývojové prostredieponúkne možnost’ doplnit’ celý textrozpísaného názvu triedy a pri tomdoplní aj potrebný import. Funkcional-itu doplnania kódu je možné vyvolat’kedykol’vek, stlacením klávesovejskratky Ctrl+Space. Kontextovúponuku, v rámci ktorej sa podl’a potrebymôže nachádzat’ aj možnost’ doplne-nia importu, ak chýba, viete vyvolat’klávesovou skratkou Alt+Enter.

Príkaz import, ktorý prostredie doplní, slúži na skrátenie zápisuplného mena triedy, ktoré obsahuje aj cestu k nej v rámci zdrojovýchsúborov, teda sk.tuke.kpi.gamelib.framework.AbstractActor.Po použití importu stací v súbore používat’ už len krátke meno Ab-stractActor. Ked’ budete potrebovat’ importovat’

nejakú triedu z poskytnutej knižnicea prostredie vám ponúkne na výber zniekol’kých možných tried s rovnakýmkrátkym názvom, tú správnu možnost’identifikujete podl’a prefixu balíkask.tuke.kpi.gamelib.

O dedicnosti toho zatial’ vel’a neviete, preto vám trochu napovieme.Zápis, ktorý hovorí o tom, že trieda A je potomkom triedy B, je nasle-dovný:

1 class A extends B {

2

3 }

Úloha 2.3

Do triedy Reactor pridajte clenské premenné, ktoré budú reprezen-tovat’ stav reaktora: aktuálnu teplotu, poškodenie a animáciu reprezentu-júcu reaktor.

Page 19: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

RED ALERT: REACTOR OVERHEAT ! 11

Jedná sa o nasledovné clenské premenné:

• temperature - aktuálna teplota reaktora, reprezentovaná celýmcíslom, pricom minimálna hodnota je 0 stupnov.

• damage - poškodenie reaktora, percentuálna hodnota, reprezento-vaná celým císlom v rozsahu od 0 (nepoškodený) do 100 (znicený).

• normalAnimation - objekt animácie, ktorá reprezentuje bezporu-chový stav reaktora. Použijeme typ Animation reprezentovanýtriedou Animation z balíka sk.tuke.kpi.gamelib.graphics.

Pri tvorbe clenských premenných nezabúdajte na to, že nechceme,aby boli vol’ne viditel’né mimo triedu!

V pocítacovej grafike (hlavne v súvislosti s 2D hrami) je možné savel’mi casto stretnút’ s termínom sprite3. Sprite je malý dvojrozmerný 3 Termín sprite vysvetlený na Wikipédii:

http://en.wikipedia.org/wiki/Sprite_(computer_graphics)

obrázok (alebo animácia), ktorý je integrovaný do väcšej scény (Obr.II.5). Efekt animácie casto vzniká postupným zobrazením niekol’kýchobrázkov (snímkov) na rovnakej pozícii (Obr. II.6).

Obr. II.5: Snímky sprite-u hlavnejpostavy hry Jet Set Willy idúcej vpravo

Obr. II.6: Výsledná animácia vytvorenápostupným vykresl’ovaním jednotlivýchobrázkov animácie kombinovaná shorizontálnym posúvaním

V hernej knižnici, ktorú používame, budeme pracovat’ s objektamitypu Animation, ktoré je možné rovnako použit’ na jednoduchéobrázky, ako aj na obrázky obsahujúce snímky animácie sprite-u.

Úloha 2.4

Vytvorte bezparametrický konštruktor triedy Reactor, v ktoromnovovytváranému objektu inicializujete premenné reprezentujúcejeho stav.

V rámci inicializácie objektu nastavte:

• animáciu, ktorá bude znázornovat’ reaktor, na obrázok reac-

tor_on.png, rozmery sprite-u nech sú 80x80, trvanie snímku 0.1sekundy (Obr. II.7),

• pociatocnú teplotu jadra reaktora na hodnotu 0, a

• pociatocnú percentuálnu hodnotu poškodenia na hodnotu 0.

Page 20: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

12 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Obr. II.7: Animácia reactor_on.png(rozmery sprite-u: 80x80, trvaniesnímku: 0.1 sekundy)

Animácie sa nachádzajú v projekte v adresári src/main/re-sources/sprites/. Pri nastavovaní cesty k animácii používajterelatívnu cestu, pricom za korenový adresár je považovaný src/-

main/resources/. Cesta k animácii reaktora preto bude vyzerat’takto: sprites/reactor_on.png.

Pri písaní ciest k súborom animá-cie môžete tiež využit’ skratkuCtrl+Space na doplnanie názvovsúborov a adresárov.

Pre nastavenie animácie využite nasledovný fragment kódu umiest-nený v konštruktore triedy Reactor:

1 // create animation object

2 normalAnimation = new Animation("sprites/reactor_on.png",

3 80, 80, 0.1f,

4 Animation.PlayMode.LOOP_PINGPONG);

5 // set actor's animation to just created Animation object

6 setAnimation(normalAnimation);

Dokumentáciu k jednotlivým triedam,ich konštruktorom a metódam môžetezískat’ priamo vo vývojovom prostredíumiestnením textového kurzora nameno požadovaného elementu apoužitím skratky Ctrl+Q. Táto skratkaje dostupná aj pocas prechádzaniazoznamom možností ponuky automat-ického doplnania kódu (Ctrl+Space).

Úloha 2.5

Overte správnost’ svojej implementácie vytvorením inštancie reaktoraa jeho vložením do hernej scény.

Pokial’ ste postupovali správne, bude vediet’ po spustení projektu(Shift+F10) pomocou inšpektora vytvorit’ inštanciu triedy Reactora umiestnit’ ju do hry (Obr. II.8).

V prípade, že sa vám nezobrazí triedaReactor v diagrame tried v inšpektore,je potrebné overit’, ci ste vytvoril trieduv správnom balíku a ci dedí od triedyAbstractActor.

Úloha 2.6

Vytvorte metódy getTemperature() a getDamage(), pomocou Všimnite si, že metóda na získanie hod-noty clenskej premennej temperaturesa volá getTemperature() a predamage sa volá getDamage(). Takétopomenovanie metód na získanie hodnôtpremenných pridaním predpony getk názvu premennej je konvencné abudeme ho casto využívat’. Výslednámetóda sa zvykne "hovorovo" nazývat’aj getter.

ktorej budete vediet’ získat’ hodnotu aktuálnej teploty jadra a jehopoškodenia.

Tieto metódy poskytujú prístup na cítanie hodnôt teploty a poško-denia. Samozrejme, ich viditel’nost’ je potrebné nastavit’ na public.Následne viete opät’ skontrolovat’ ich funkcionalitu pomocou inšpek-tora.

Page 21: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

RED ALERT: REACTOR OVERHEAT ! 13

Obr. II.8: Plne funkcný reaktor

Krok 3: Intermezzo - Method Overloading

Teraz, ked’ už vieš, ako vytvorit’ triedu a jej metódy, ukážeme ti jednuz užitocných vlastností polymorfizmu (ku ktorému sa ešte viackrátvrátime). Tou vlastnost’ou je pret’aženie metód (anglicky method overload-ing).

Úloha 3.1

V balíku sk.tuke.kpi.oop.game vytvorte triedu Computer akopotomka triedy AbstractActor.

Ako animáciu použite sprite obrázok computer.png (Obr. II.9).

Obr. II.9: Animácia computer.png(rozmery sprite-u: 80x48, trvaniesnímku: 0.2 sekundy)

Úloha 3.2

V triede Computer vytvorte metódy pre vykonanie základnýcharitmetických operácií add() a sub() pre císelné údajové typy int afloat.

Page 22: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

14 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Každá z týchto metód bude mat’ 2 parametre rovnakého typu preoperandy danej aritmetickej operácie. Ked’že raz to budú parametretypu int, raz float, implementáciou takýchto metód nastane ich tzv.pret’aženie. To, ktorá konkrétna metóda z dvoch

možných pre meno add (a taktiežsub) bude zavolaná, je urcené statickypocas prekladu kódu na základe typovargumentov dodaných vo volanímetódy.

Implementáciu si môžete overit’ pomocou nástroja Inšpektor.

Krok 4: Reactor (Over)Heating

Spät’ k reaktoru! Získat’ jeho stav už vieš, teraz sa pozrieme na to, akojeho stav menit’.

Úloha 4.1

Vytvorte metódu increaseTemperature(), pomocou ktorej budemožné zvýšit’ aktuálnu teplotu jadra reaktora.

Táto metóda nebude vracat’ žiadnu hodnotu a bude mat’ jedencelocíselný parameter (pomenovaný napr. increment), ktorý budereprezentovat’ hodnotu, o ktorú sa má aktuálna teplota jadra zvýšit’.

Pri implementovaní metódy však zohl’adnite nasledovné sku-tocnosti:

• S nárastom teploty lineárne zvyšujte poškodenie reaktora. Reaktorsa zacne kazit’ po prekrocení teploty 2000 stupnov a prestane byt’funkcný po dosiahnutí 6000 stupnov (Obr. II.10). Následné ochlade-nie reaktora ale nezníži úroven poškodenia, ktoré už vysoká teplotaspôsobila (to znamená, že po volaní tejto metódy nemôže byt’ hod- Znižovanie poškodenia reaktora bude

možné jedine jeho opravou, ktorúbudete riešit’ nabudúce.

nota poškodenia reaktora nižšia ako pred jej volaním). Pri výpocteúrovne poškodenia zaokrúhl’ujte desatinnú cast’ výsledku nadol.

020406080

100

0 1000 2000 3000 4000 5000 6000

pošk

oden

ie (%

)

teplota (°C)

Obr. II.10: Závislost’ zvyšovania poško-denia reaktora pri raste jeho teploty

• Ak teplota po zvýšení prekrocí hodnotu 4000 stupnov, vzhl’adreaktora bude od tohto momentu reprezentovaný animácioureactor_hot.png (Obr. II.11)

• Ak je poškodenie reaktora v intervale <33%, 66%>, teplota rastie1.5-násobne; ak prekrocí hodnotu 66%, teplota porastie dvojná-sobne. V oboch prípadoch je zmena uvedená oproti pôvodnej

Page 23: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

RED ALERT: REACTOR OVERHEAT ! 15

Obr. II.11: Animácia reactor_-hot.png (rozmery sprite-u: 80x80,trvanie snímku: 0.05)

hodnote parametra increment. Po výpocte novej hodnoty teplotyvýsledok zaokrúhlite vždy nahor na najbližšie celé císlo.

• Ak teplota po zvýšení dosiahne (alebo prekrocí) hodnotu 6000stupnov, dôjde ku zniceniu reaktora (poškodenie reaktora dosiahnehodnotu 100%). Znicený reaktor bude reprezentovaný animácioureactor_broken.png (Obr. II.12).

Obr. II.12: Animácia reactor_-broken.png (rozmery sprite-u: 80x80,trvanie snímku: 0.1)

Je výhodné vytvorit’ objekty animáciíuž pri inicializovaní objektu a ichhodnoty uložit’ do d’alších clenskýchpremenných. Ked’že reaktor sa môženachádzat’ v niekol’kých stavoch(v našom prípade v troch - stav ok,prehriaty a znicený reaktor), animáciereprezentujúce tento stav sa budúmenit’. Ak sa v priebehu hry zmení stavreaktora napr. 50x, znamená to, že prikaždej zmene potrebujete nacítavat’inú animáciu zvlášt’ - spolu teda 50nacítaní súborov animácií. Ak si všakvšetky animácie nacítate pri inicializáciiobjektu, nacítate spolu iba 3 súboryanimácií, ktoré budete môct’ striedat’podl’a potreby.

• Ak poškodenie reaktora dosiahlo hodnotu 100%, akékol’vek d’alšiezvyšovanie teploty už nemá žiadny efekt.

Úloha 4.2

Vytvorte metódu decreaseTemperature(), pomocou ktorej budemožné znížit’ aktuálnu teplotu jadra reaktora.

Táto metóda nebude vracat’ žiadnu hodnotu a bude mat’ jedencelocíselný parameter (pomenovaný napr decrement), ktorý budereprezentovat’ hodnotu, o ktorú sa má aktuálna teplota jadra znížit’.Pozor, zníženie teploty neznižuje poškodenie, ktoré vysoká teplota užspôsobila!

Pri implementovaní metódy zohl’adnite nasledovné skutocnosti:

• Ak je poškodenie jadra aspon 50%, reálne znižovanie teploty budelen polovicné oproti hodnote parametra decrement.

• Ak je poškodenie jadra na úrovni 100%, znižovanie teploty užnemá žiaden efekt.

• Ak teplota jadra pri ochladzovaní klesne na 4000 stupnov alebomenej, zmente animáciu reprezentujúcu stav reaktora na reac-tor_on (Obr. II.7).

Page 24: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

16 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 4.3

Vytvorte metódu updateAnimation(), ktorá na základe aktuálnejteploty nastaví animáciu reaktora.

Pri pozornom pohl’ade na metódy increaseTemperature() adecreaseTemperature() si všimnete, že obe metódy riešia nas-tavenie správnej animácie reaktora v závislosti na jeho teplote. Takátoduplicita je však zbytocná a komplikuje prípadnú zmenu funkcional-ity. Preto refaktorujte svoj kód tak, že túto spolocnú funkcionalituoddelíte do samostatnej metódy updateAnimation().

Úloha 4.4

Upravte implementáciu metód increaseTemperature() a de-creaseTemperature() tak, aby ste pre zmenu aktuálnej animácievyužili práve vytvorenú metódu updateAnimation(). Metóda updateAnimation()

reprezentuje len implementacný de-tail a nie je potrebné (ba dokonca anižiadúce) aby bola dostupná použí-vatel’om objektu reaktora. Skryte pretotúto metódu vhodným modifikátoromviditel’nosti.

Po refaktorizácii z predchádzajúcej úlohy nezabudnite zmenit’ ajpôvodné metódy, kde sa extrahovaný kód nachádzal, aby vyžívalinovú metódu.

Úloha 4.5

Pomocou Inšpektora umiestnite objekt reaktora do mapy a otestujtesprávnost’ svojej implementácie (Obr. II.13).

Obr. II.13: Pokazený (prehriaty) reaktor

Page 25: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

RED ALERT: REACTOR OVERHEAT ! 17

Doplnujúce úlohy

Úloha A2.1

Ošetrite prípad, kedy sa pri volaní metód increaseTemperature()

a decreaseTemperature() použije záporný parameter.Ak k takémuto volaniu dôjde, nevykonajte žiadnu zmenu teploty.

Úloha A2.2

Upravte reaktor tak, aby rýchlost’ pulzovania jeho animácie záviselaod úrovne poškodenia.

Pri vyššom poškodení reaktora by trvanie jedného snímku animá-cie malo byt’ kratšie, pre dosiahnutie efektu rýchlejšieho pulzovaniareaktora.

Page 26: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav
Page 27: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

IIIPowering DevicesJeden reaktor dokáže napájat’ jedno svetlo... Zatial’...

MOTIVÁCIA

Vitaj pri brífingu d’alšej misie, kadet! Úvodné zahrievacie kolo máš úspešne za sebou a spolu s našimtaktickým a strategickým tímom predpokladáme, že si sa urcite dostatocne zahrial pri ovládaní reaktora.

Pri plnení rôznych misií v teréne sa ti však urcite hodí niekol’ko zrucností, ktoré získaš pocas dnešnéhotréningu. Jedná sa hlavne o zrucnost’ používania referencných typov ako parametrov metód. Táto nená-padná zrucnost’ už zachránila život nejednému objektovému programátorovi, preto ju nepodcenuj!

Vel’a št’astia pri dosahovaní ciel’ov dnešnej misie! Z velitel’ského mostíka zdraví Manager.

C IELE

1. Osvojit’ si použitie kl’úcového slova this vo vlastnom kóde.

2. Osvojit’ si tvorbu parametrických konštruktorov.

3. Porozumiet’ využitiu referencie na objekt ako parametra metódy.

Krok 1: First tools

Ako ste si všimli, pracovat’ s atómovým reaktorom nie je žiadnasranda. Hlavne ked’ sa zacne prehrievat’ a neexistuje spôsob, ako hoopravit’...

<<abstract>>AbstractActor Hammer

Obr. III.1: Diagram tried, ktorývyjadruje vzt’ah tried Hammer aAbstractActor.

Úloha 1.1

V balíku sk.tuke.kpi.oop.game vytvorte triedu Hammer, ktorábude reprezentovat’ kladivo.

Page 28: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

20 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Animácia reprezentujúca kladivo na mape je uložená v súborehammer.png (Obr. III.2). Kladivo bude mat’ clenskú premennúpre pocet zostávajúcich použití, ktorú inicializujte prostredníctvomkonštruktora na hodnotu 1. Premennej nastavte vhodnú viditel’nost’ aprístup k nej zabezpecte patricnou get metódou. Obr. III.2: Animácia hammer.png

(rozmery sprite-u: 16x16)

Úloha 1.2

Pridajte do triedy Hammer metódu use(), ktorá bude reprezentovat’použitie kladiva. Každý aktér zobrazený v hre sa

nachádza v aktívnej hernej scéne,na ktorú má aj dostupnú referenciu.Do scény môžeme aktérov pridávat’aj odoberat’. Využite možnosti vývo-jového prostredia a nájdite spôsob,ako získat’ referenciu na hernú scénua ako pomocou nej odstránit’ použitékladivo z hry. Pomôct’ vám môženapríklad funkcionalita doplnania kódu,ktorú aktivujete klávesovou skratkouCtrl+Space.

Pri každom použití je potrebné aktualizovat’ pocet zostávajúcichpoužití kladiva. Ked’ tento pocet dosiahne 0, kladivo odstránte zhernej scény (kladivo sa zlomilo).

Krok 2: If all you have is a hammer, everything looks like a nail

V tomto kroku sa pokúsime poškodený reaktor vcas opravit’ vhod-ným nástrojom: kladivom.

Hammer

Reactoruses

<<abstract>>AbstractActor

Obr. III.3: Diagram tried, ktorý vy-jadruje vzt’ah tried Reactor a Hammer.

Úloha 2.1

Vytvorte v triede Reactor metódu repairWith(), pomocou ktorejbude možné reaktor opravit’. Ked’že zvyšovaním teploty rastie poško-

denie lineárne, po znížení poškodeniaje potrebné odpovedajúcim spôsobomznížit’ aj teplotu. K tejto casti úlohy savrátite neskôr v rámci doplnujúcichúloh.

Metóda nebude nic vracat’, ale bude mat’ jeden parameter typuHammer. Jej správanie bude nasledovné:

• Metóda bude pracovat’ iba vtedy, ak hodnota parametra metódyobsahuje referenciu na inštanciu triedy Hammer (a teda nie je null) areaktor má hodnotu poškodenia vyššiu ako 0% ale ešte nie je úplneznicený.

• Použitie kladiva zníži poškodenie reaktora o hodnotu 50. Pozor alena to, aby výsledná hodnota poškodenia neklesla pod 0. Teda, akbude reaktor poškodený, povedzme, na 92%, po použití kladivajeho poškodenie klesne na 42%. A ak bude poškodený na 35%,použitím kladiva sa úplne opraví (poškodenie 0%).

Page 29: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

POWERING DEVICES 21

Pri implementácii nezabudnite na to, že okrem úrovne poškodeniaa teploty je potrebné zmenit’ aj obrázok, ktorý vizualizuje teplotureaktora. Predíd’te však duplikovaniu kódu!

Úloha 2.2

Overte správnost’ svojej implementácie.Vytvorte na mape inštanciu reaktora a niekol’kých kladív. Následne

reaktor prehrejte a pokúste sa ho opravit’ použitím kladiva.

Krok 3: Shutting Down Reactor

Výborne! Reaktor už zvládame opravit’, aj ked’ sa nadmieru prehreje(škoda, že v skutocnosti nestací len to kladivo). Teraz by sa zišlo nájst’spôsob, ako reaktor v prípade potreby uviest’ do necinnosti alebo honaopak naštartovat’.

Úloha 3.1

V triede reaktora vytvorte metódy turnOn() a turnOff(), pomo-cou ktorých bude možné reaktor zapnút’ a vypnút’.

Pri implementácii nezabudnite na fakt, že reaktor vie pracovat’ lenvtedy, ak je zapnutý (ak nebude zapnutý, nebude možné mu zvyšovat’ani znižovat’ teplotu pomocou jeho metód). Rovnako zabezpecte, abyreaktor nebol zapnutý automaticky po vytvorení jeho inštancie. Popokazení reaktora, zabezpecte, aby bol vo vypnutom stave. Urobteteda všetky potrebné úpravy, aby ste tieto skutocnosti zohl’adnili.

Úloha 3.2

Pre reprezentáciu reaktora vo vypnutom stave použite obrázok an-imácie reactor.png (Obr. III.4). V prípade, že sa reaktor vypnedôsledkom znicenia, zabezpecte, aby ako jeho animácia ostal nas-tavený obrázok reactor_broken (Obr. II.12).

Obr. III.4: Animácia reactor.png(rozmery sprite-u: 80x80)

Potrebný objekt animácie si pripravte v konštruktore reaktora,patricne upravte metódu nastavujúcu aktuálnu animáciu a právevytvorené metódy turnOn() a turnOff().

Úloha 3.3

V triede Reactor vytvorte metódu isRunning(), ktorá zistí, ci jereaktor zapnutý (vráti hodnotu true) alebo vypnutý (vráti hodnotufalse).

Page 30: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

22 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Krok 4: Gaining Control

Ovládanie rozhorúceného reaktora môže byt’ poriadne nebezpecnázáležitost’. Preto sa teraz pokúsime vytvorit’ dial’kový ovládac, ktorýnám umožní reaktor zapnút’ alebo vypnút’ bez priameho fyzickéhokontaktu s ním.

Controller

Reactor<<abstract>>AbstractActor

Obr. III.5: Diagram tried, ktorývyjadruje vzt’ah tried Reactor aController.

Úloha 4.1

Vytvorte triedu Controller, ktorá bude reprezentovat’ ovládac prepríslušný reaktor.

Obrázok ovládaca sa nachádza v súbore switch.png (Obr. III.6). Obr. III.6: Animácia switch.png(rozmery sprite-u: 16x16)Trieda bude mat’ len jednu clenskú premennú reactor, ktorá

bude predstavovat’ referenciu na ovládaný reaktor. Jej hodnotu nas-tavte pri volaní konštruktora, ktorému bude referencia na príslušnýreaktor odovzdaná.

Úloha 4.2

Vytvorte vo vypínaci metódu toggle(), ktorá zapne/vypne ovlá-daný reaktor.

Úloha 4.3

Overte správnost’ svojej implementácie.Pomocou nástroja Inšpektor vytvorte niekol’ko inštancií reaktorov

a ku každému potrebný vypínac. Overte funkcnost’ vypínacov (Obr.III.7).

Krok 5: Powering Light

Reaktor, ktorý ste implementovali minulý týžden a opravili dnes,vyrába elektrinu. V tomto kroku vytvoríme spotrebic, ktorý ku reak-toru pripojíme. Samozrejme - bude fungovat’ len vtedy, ak budereaktor vyrábat’ elektrinu.

Page 31: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

POWERING DEVICES 23

Obr. III.7: Štyri bloky reaktorov ovlá-dané štyrmi vypínacmi. Ktorý všakovláda ktorý?

Reactor+addLight()

+removeLight() Light+toggle()

+setElectricityFlow()

<<abstract>>AbstractActor

Obr. III.8: Diagram tried, ktorý vy-jadruje vzt’ah tried Light, Reactor aAbstractActor.

Page 32: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

24 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 5.1

Podl’a diagramu tried vyššie, vytvorte v balíku sk.tuke.kpi.oop.game

triedu Light, ktorá bude reprezentovat’ svetlo a otestujte svoju imple-mentáciu.

Trieda bude mat’ dve metódy:

• toggle() - Metóda bude vediet’ zmenit’ stav svetla zo zapnutéhona vypnuté a naopak. Svetlo však bude reálne svietit’ (jeho an-imácia bude light_on - Obr. III.9) len v tom prípade, ak budenapájané elektrinou.

Nezabudnite, že svetlo sa má zasvietit’aj vtedy, ak je vypínac prepnutý dopolohy zapnutý a práve ho pripojím kdodávke elektriny!

• setElectricityFlow() - Metóda bude mat’ jeden parametertypu boolean, ktorý bude udávat’, ci je svetlu elektrika poskyto-vaná alebo nie.

Obr. III.9: Animácia light_on.png(rozmery sprite-u: 16x16)

Obr. III.10: Animácia light_off.png(rozmery sprite-u: 16x16)

Ako animáciu zasvieteného svetla použite súbor light_on (Obr.III.9) a animáciu zhasnutého svetla použite súbor light_off (Obr.III.10).

Úloha 5.2

V triede reaktora vytvorte metódy addLight() a removeLight(),pomocou ktorých budete vediet’ k reaktoru pripojit’ a odpojit’ svetlo.

Aktuálny model reaktora bude vediet’ súcasne napájat’ práve jedenspotrebic - v našom prípade to bude práve jedno svetlo. Referenciunan dostanete ako parameter v metóde addLight().

Pri volaní metód nezabudnite aktualizovat’ aj stav napájania spotre-bica vzhl’adom na stav reaktora - ak je zapnutý a nie je pokazený, takreaktor elektrinu vyrába. Nezabudnite rovnako aktualizovat’ aj všetkyostatné potrebné metódy, ktoré sa podiel’ajú na uvedenej zmene stavu.

Úloha 5.3

Overte správnost’ svojej implementácie vytvorením dvoch inštanciíreaktorov a k nim pripojte dve inštancie svetiel.

Pri overovaní cinnosti sa môžete riadit’ nasledovnou pravdivost-nou tabul’kou, ktorá ilustruje správanie svetla:

isOn isPowered stav svetlatrue true svietitrue false nesvietifalse true nesvietifalse false nesvieti

Page 33: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

POWERING DEVICES 25

Obr. III.11: Každý reaktor napája jednosvetlo (jeden už zrejme donapájal).

Doplnujúce úlohy

Úloha A3.1

V rámci opravy reaktora kladivom v metóde repairWith() zod-povedajúco upravte aj teplotu reaktora.

Vrát’te sa k úlohe 4.1 minulého cvicenia (Kapitola II) a všimnite siuvedený graf závislosti poškodenia od teploty. Ak ho invertujemepre získanie závislosti teploty od poškodenia, tak jeho správanie voblasti 0% poškodenia nie je pre výpocet teploty jednoznacné (nieje to funkcia). Preto výpocet teploty pri oprave reaktora upravtenasledovne:

• Najskôr urcte vzt’ah teploty od poškodenia na základe casti grafu,kde je ich závislost’ lineárna.

• Urcte pomocnú hodnotu poškodenia (zníženú o 50 oproti hodnotepred opravou) bez ohl’adu na to, ci výsledok bude kladné alebozáporné císlo.

• Získanú hodnotu dosad’te do pripraveného vzt’ahu a výsledoknastavte ako teplotu reaktora po oprave, avšak len ak by nováteplota reaktora bola nižšia ako tá pred opravou.

Úloha A3.2

Vytvorte triedu pre Thorovo kladivo s názvom Mjolnir, odvodenúod triedy Hammer.

Page 34: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

26 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Mjolnir Vydrží 4 použitia (úplná oprava dvoch reaktorov), poktorých sa, tak ako pôvodné kladivo, tiež zlomí.

Úloha A3.3

Vytvorte triedu FireExtinguisher pre hasiaci prístroj, ktorýmbude možné uhasit’ horiaci znicený reaktor. Obr. III.12: Animácia

extinguisher.png (rozmery sprite-u:16x16)Trieda bude potomkom triedy AbstractActor a bude mat’ clen-

skú premennú pre pocet použití, ktorej nastavte vhodnú viditel’nost’,a implementujte aj patricnú get metódu. Trieda nech má aj metóduuse() na odrátavanie zostávajúceho poctu použití. Ked’ sa hasiaciprístroj spotrebuje, zmizne z hernej mapy. Animácia reprezentujúcahasiaci prístroj na mape je uložená v súbore extinguisher.png(Obr. III.12).

Na uhasenie implementujte v triede Reactor metódu extin-

guishWith(), ktorá bude ako parameter vyžadovat’ objekt typuFireExtinguisher, ktorý sa na hasenie použije. Hasiaci prístrojvydrží jedno použitie, pri ktorom sa teplota reaktora zníži na 4000stupnov a animácia reaktora sa zmení na obrázok reactor_ex-

tinguished.png (Obr. III.13). Poškodenie reaktora sa uhasenímnezmení.

Obr. III.13: Animácia reactor_-extinguished.png (rozmery sprite-u:80x80)Doplnujúce zdroje

• Java Tutoriál: What Is an Object?http://download.oracle.com/javase/tutorial/java/concepts/object.html

• Java Tutoriál: What Is a Class?http://download.oracle.com/javase/tutorial/java/concepts/class.html

• Java Tutoriál: What Is Inheritance?http://docs.oracle.com/javase/tutorial/java/concepts/inheritance.html

Page 35: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

IVAnd... Action!

MOTIVÁCIA

Kadet! Aby si obstál v boji s objektmi v nehostinnom svete Objektového programovania, potrebuješ sazoznámit’ s dôležitou vlastnost’ou, ktorú niektoré objekty používajú na svoje maskovanie a oklamanienepriatel’a formou polymorfizmu. Touto vlastnost’ou nie je nic iné, ako dedicnost’!

Náš taktický a strategický tím pre zdokonalenie tvojich schopností obstát’ v tomto boji pripravil cvicnúmisiu s kódovým oznacením Mission: Inheritance. Sú pre teba pripravené ciele, ktoré ti pomôžu porozu-miet’ objektom využívajúcim túto vlastnost’. Po ich dosiahnutí sa tvoja šanca prežit’ vo svete Objektovéhoprogramovania dramaticky zvýši! Preto postupuj podl’a pripraveného plánu misie.

Vel’a št’astia pri zdolávaní ciel’ov! Z velitel’ského mostíka zdraví Manager.

C IELE

1. Precvicit’ si dedicnost’.

2. Porozumiet’ prekrývaniu metód.

3. Porozumiet’ princípu polymorfizmu.

4. Naucit’ sa používat’ kl’úcové slovo super.

5. Osvojit’ si použitie referencie na metódu.

Krok 1: Similarity (not) entirely coincidental

Kadet! Nepochybuj o tom, že pôvod kladiva Mjolnir je jednoznacneextraterestriálny, a hoci oplýva nadl’udskou mocou, chtiac-nechtiacmá nejaké spolocné crty s hasiacim prístrojom. Dá sa použit’ a casomsa znicí.

<<abstract>>BreakableTool

<<abstract>>AbstractActor

Obr. IV.1: Abstraktná triedaBreakableTool reprezentujúcapoškoditel’ný nástroj.

Page 36: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

28 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 1.1

Vytvorte abstraktnú triedu BreakableTool, ktorá predstavujezovšeobecnenie pre akýkol’vek pracovný nástroj, ktorý má obmedzenýpocet použití. Pomôžte si kódom, ktorý ste implemen-

tovali už pri kladive alebo hasiacomprístroji.

V triede nech je clenská premenná remainingUses pre pocetzostávajúcich použití nástroja, ktorú je potrebné sprístupnit’ zvonkutriedy len na cítanie a inicializovat’ použitím parametrického konštruk-tora. Vytvorte metódu use() na odrátavanie použití nástroja a najeho odstránenie z mapy, ked’ pocet použití klesne na 0 (nástroj saopotreboval a zlomil).

Úloha 1.2

Upravte triedy Hammer a FireExtinguisher, aby boli potomkomtriedy BreakableTool.

Nezabudnite na úpravu konštruktora týchto tried a odstránenieduplicitného kódu.

Úloha 1.3

Vytvorte nový balík sk.tuke.kpi.oop.game.tools a presunte doneho triedy týkajúce sa nástrojov. Pri tejto úlohe viete využit’ možnosti

refaktorizácie, ktoré ponúka vývojovéprostredie. Vyhnete sa tak manuálnemuprepisovaniu package deklaráciena zaciatku súborov a upravovaniuimport-ov.

V projekte sa už zväcšuje pocet tried. Aby ste si v nich zachovaliporiadok a zoskupili spolu súvisiace triedy, vytvorte pre nástrojenový balík tools v balíku sk.tuke.kpi.oop.game a presunte tamtriedu BreakableTool, ako aj Hammer, Mjolnir a FireExtin-guisher.

Krok 2: Self-exploding reactor

Doteraz ste mohli s reaktorom pracovat’ výlucne manuálne - vedeli steho zapnút’ a vypnút’ a vedeli ste mu zvýšit’ a znížit’ teplotu volanímvhodných metód. V tomto kroku však vykonáte potrebné úpravy nato, aby vedel reaktor pracovat’ samostatne. Využijeme na to systémakcií, ktoré budú reprezentovat’ cinnost’ alebo správanie aktéra vhernej scéne.

Akcia, reprezentovaná rozhraním Action a jeho všeobecnou im-plementáciou AbstractAction, slúži v hernej knižnici GameLib nazapúzdrenie cinností aktérov do samostatných objektov. Naplánovanímvykonávania akcie na scéne, do ktorej aktér patrí, potom dôjde k jej(postupnému) vykonaniu (realizácia návrhového vzoru Command1). 1 Návrhový vzor Command je popísaný

napríklad na stránke SourceMaking:https://sourcemaking.com/design_patterns/command

Všetky akcie naplánované na scéne, ktoré ešte neboli dokoncené, savykonávajú vždy pred vykreslením nového snímku scény na obra-

Page 37: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

AND . . . ACTION ! 29

<<interface>>Actor

<<abstract>>AbstractActor

<<interface>>Scene

0..10..*

<<interface>>Action 0..*

<<abstract>>AbstractActionPerpetualReactorHeating

Obr. IV.2: Vzt’ahy medzi aktérom,scénou a akciou.

zovku (v prípade štandardnej rýchlosti snímkov je to 60x za sekundu).Pomocou akcií je možné implementovat’ správanie aktéra vzhl’adomna plynúci cas, resp. reakcie aktéra na aktuálne dianie v scéne.

Vo všeobecnosti má každá akcia

• stav reprezentovaný dvoma clenskými premennými:

– actor (getter getActor()) - aktér, s ktorým sa akcia vykonáva(referenciu nastaví scéna pri naplánovaní akcie),

– isDone (getter isDone()) - vyjadruje, ci sa akcia už ukoncila(kontrolované scénou vždy pred vykonaním akcie),

• a dve podstatné metódy:

– execute(float deltaTime) - metóda implementujúcalogiku akcie, volaná vždy pred vykreslením nového snímkuscény (v prípade, že akcia bola naplánovaná a nie je ešte ukoncená).Parametrom metódy je cas (v sekundách) od poslednéhovykresl’ovania scény,

– reset() - umožnuje resetovat’ stav akcie.

Úloha 2.1

V novom balíku sk.tuke.kpi.oop.game.actions vytvorte trieduPerpetualReactorHeating, ktorá bude reprezentovat’ akciupostupného zvyšovania teploty reaktora. Konkrétnu hodnotu krokuzvyšovania teploty umožnite špecifikovat’ pri vytváraní inštancietriedy v konštruktore.

Ako je možné vidiet’ aj z diagramu tried uvedenom vyššie, novátrieda akcie PerpetualReactorHeating má dedit’ od triedy Ab-

stractAction z balíka sk.tuke.kpi.gamelib.framework.actions.Trieda AbstractAction používa typový parameter, ktorým je

definovaný typ aktéra, s ktorým sa môže akcia vykonávat’. Ked’žemá akcia zvyšovat’ teplotu reaktora, použite ako hodnotu typovéhoparametra typ Reactor:

Page 38: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

30 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

1 public class PerpetualReactorHeating extends AbstractAction<Reactor> {

2

3 }

Úloha 2.2

V triede PerpetualReactorHeating prekryte abstraktnú metóduexecute(), v ktorej implementujete cinnost’ akcie.

Pri implementovaní metódy execute() získajte referenciu naaktéra, s ktorým sa akcia vykonáva (reaktor) a zvýšte jeho teplotu ohodnotu danú parametrom konštruktora akcie. Vynechanie typového parametra vo

volaní metódy getActor() triedyAbstractAction spôsobí to, žemetóda getActor() bude mat’ akotyp návratovej hodnoty typ Actor ateda nebude možné zavolat’ metódureaktora increaseTemperature()bez pretypovania.

Úloha 2.3

Naplánujte vykonávanie akcie PerpetualReactorHeating nareaktore tak, aby sa teplota zvyšovala vždy o 1 stupen.

Ked’že pre naplánovanie akcie potrebuje aktér poznat’ scénu, doktorej patrí, vhodným miestom pre naplánovanie akcie môže byt’metóda addedToScene() zdedená od triedy AbstractActor, ktoráv parametri dostane referenciu na scénu (typ Scene) a je zavolaná potom, co bol aktér do danej scény pridaný. Metódu addedToScene()

je teda potrebné prekryt’. Nezabudnite však na to, že stále potrebu-jeme, aby sa pôvodná implementácia metódy addedToScene()

z triedy AbstractActor vykonala, a teda využite kl’úcové slovosuper na zavolanie zdedenej implementácie!

Scéna definuje metódu scheduleAction(), ktorá akceptujeakciu a aktéra, s ktorým má akciu neskôr vykonávat’. Naplánovanievykonávania akcie v metóde reaktora môže preto vyzerat’ nasledovne:

1 // v metode addedToScene triedy Reactor

2 scene.scheduleAction(new PerpetualReactorHeating(1), this);

Náš taktický a strategický tím však odporúca využit’ doplnkovúmetódu scheduleOn() dostupnú priamo na akcii, ktorá akceptujeaktéra a zabezpecí to isté, ako metóda scheduleAction() na scéne,len s o nieco prehl’adnejším zápisom:

1 // v metode addedToScene triedy Reactor

2 new PerpetualReactorHeating(1).scheduleOn(this);

Page 39: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

AND . . . ACTION ! 31

Úloha 2.4

Overte správnost’ svojej implementácie spustením reaktora.Ak ste postupovali správne, zapnutému reaktoru sa bude pos-

tupom casu zvyšovat’ teplota, co si viete overit’ pomocou inšpektora.

Krok 3: How cool is cool enough?

Teraz, ked’ máme prvý krok k vytvoreniu samocinného aktéra zasebou, urcite neuniklo vašej pozornosti, že len na volanie jednejmetódy reaktora bola vytvorená celá nová trieda. Tento nedostatokprvotného riešenia sa pokúsime postupne riešit’.

Úprava reaktora z predchádzajúceho kroku má však jeden hácik- tým, že necháte reaktor pracovat’ samostatne, bude sa systemat-icky prehrievat’. A prehrievanie, ako vieme už od roku 19862, bude 2 http://en.wikipedia.org/wiki/

Chernobyl_disasternevyhnutne viest’ k jeho trvalému poškodeniu. Aby sme sa vyhlitakejto situácii, namiesto kladív vytvoríte chladic, ktorý bude reaktorsystematicky ochladzovat’.

Cooler

Reactor<<abstract>>AbstractActor

Obr. IV.3: Vzt’ah tried Reactor aCooler.

Úloha 3.1

V balíku sk.tuke.kpi.oop.game vytvorte triedu Cooler prechladic, ktorý bude zabezpecovat’ dostatocné chladenie pre pripojenýreaktor.

Správanie chladica a jeho vzt’ah s reaktorom opisuje nasledujúcidiagram tried:

Cooler+Cooler(Reactor)

+turnOn()+turnOff()+isOn()

Reactor

Obr. IV.4: Trieda Cooler.

Ako animáciu chladica použite súbor fan.png (Obr. IV.5). Ked’bude chladic vypnutý, tak prehrávanie jeho animácie pozastavte. Ked’chladic naopak zapnete, jeho animáciu spustite. Na objekte animácienájdete vhodné metódy na jej ovládanie. Obr. IV.5: Animácia fan.png (rozmery

sprite-u: 32x32, trvanie snímku: 0.2).

Page 40: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

32 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 3.2

Do triedy Cooler pridajte privátnu metódu, v ktorej implementujetecinnost’ chladica.

Metódu pomenujte napríklad coolReactor(). Pri jej zavolaní savždy (teda - ak je chladic zapnutý) zníži teplota pripojeného reaktorao jeden stupen.

Úloha 3.3

Prekryte metódu addedToScene(), v ktorej naplánujete akciu precinnost’ chladica.

Pre zavolanie metódy v rámci akcie nie je potrebné vytvárat’ celútriedu akcie, ktorá potom slúži len na jednu, vel’mi špecifickú funkciu.Teraz však využijeme akciu Invoke (dostupnú v knižnici GameLib),ktorou môžeme definovat’ cinnost’ akcie (metóda execute()) ajreferenciou na metódu implementujúcou požadované správanie.

Referencia na metódu method konkrétneho objektu object má vjazyku Java zápis v tvare object::method, používa sa teda operátordvojitej dvojbodky.

Akciu a jej naplánovanie teda zapíšeme takto:

1 // v metode addedToScene triedy Cooler

2 new Invoke<>(this::coolReactor).scheduleOn(this);

Takáto akcia však celkom nesplní to, co od nej cakáme: metóducoolReactor() zavolá iba raz a potom je považovaná za skoncenú(isDone() vráti true). Opakované vykonávanie akcie vieme do-cielit’ využitím akcie Loop (dostupná v GameLib), ktorá akceptujeinú akciu ako parameter konštruktora a stále je považovaná zaneskoncenú (isDone() akcie Loop stále vráti false):

Akcia Loop implementujenávrhový vzor Decorator (https://sourcemaking.com/design_patterns/decorator).

1 // v metode addedToScene triedy Cooler

2 new Loop<>(new Invoke<>(this::coolReactor)).scheduleOn(this);

Úloha 3.4

Overte správnost’ svojej implementácie spustením reaktora a pripo-jením najprv jedného a potom dvoch chladicov naraz (Obr. IV.6).

Cím viac chladicov pripojíte, tým skôr bude reaktor ochladený.Pozor však na to, že reaktor nie je možné chladit’ do mínusovýchteplôt.

Page 41: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

AND . . . ACTION ! 33

Obr. IV.6: Pracovnú teplotu reak-tora práve zabezpecujú dva chladicesúcasne.

Krok 4: Defective Light

Náš analytický tím zadefinoval pokazené svetlo, ako svetlo, ktoré jepokazené. A ked’že môžeme predpokladat’, že pokazené svetlo bolonajprv v poriadku, jeho správanie odvodíme od dobrého svetla. Vnašom prípade sa bude pokazenost’ prejavovat’ blikaním svetla vnepravidelných intervaloch.

Light DefectiveLight<<abstract>>AbstractActor

Obr. IV.7: Dedicná línia triedyDefectiveLight

Úloha 4.1

V balíku sk.tuke.kpi.oop.game vytvorte triedu Defective-

Light, ktorá bude potomkom triedy Light.

Úloha 4.2

V triede DefectiveLight vytvorte metódu, ktorá bude definovat’správanie pokazeného svetla.

Pre dosiahnutie efektu pokazeného svetla môžete použit’ l’ubovol’nýpostup. Jeden z nich môže vyzerat’ napr. tak, že vygenerujete náhodnécíslo od 0 do 20 a ak bude vygenerované císlo 1, zmeníte stav svetla(zo zhasnutého na zasvietené a opacne).

Page 42: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

34 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Náhodné císlo môžte v Jave získat’ pomocou inštancie triedy Ran-

dom 3 alebo jednoducho volaním statickej metódy Math.random()4. 3 https://docs.oracle.com/javase/10/docs/api/java/util/Random.html4 https://docs.oracle.com/javase/10/docs/api/java/lang/Math.html#random()

Úloha 4.3

Naplánujte správanie pokazeného svetla pomocou akcií Loop aInvoke.

Úloha 4.4

Overte správnost’ svojej implementácie vytvorením pokazenéhosvetla a jeho pripojením k reaktoru.

Nezabudnite, že typ parametra metódy addLight() v triedeReactor netreba menit’. Práve tu je využitá vlastnost’ polymorfizmu:DefectiveLight, ako potomok triedy Light, sa dá použit’ všadetam, kde je akceptovaný typ Light.

Obr. IV.8: okazené svetlo rozpoznáte oddobrého svetla na základe jeho cinnosti.

Doplnujúce úlohy

Úloha A4.1

Vytvorte triedu SmartCooler predstavujúcu upravený Cooler,ktorý sa automaticky zapína a vypína v závislosti od teploty reaktora. Nezabudnite na to, že cast’ funkcionality

chladica je už riešená v triede Cooler.Vyhnite sa duplikovaniu kódu a využitemožnost’ volat’ metódy predka.

Pomocou smart chladica zabezpecte udržiavanie pracovnej teplotyreaktora v rozsahu od 1500 do 2500 stupnov. To znamená, že chladicbude chladit’ len vtedy, ak aktuálna teplota stúpne nad 2500 stupnov.

Page 43: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

AND . . . ACTION ! 35

Ak však teplota klesne pod 1500 stupnov, chladic prestane reaktorchladit’.

V tomto prípade bude tiež zaujímavé sledovat’, ako sa chladic budezapínat’ a vypínat’ podl’a toho, kedy bude naozaj pracovat’.

Úloha A4.2

Vytvorte triedu Helicopter pre bojovú helikoptéru, ktorá budevediet’ prenasledovat’ hráca a zaútocit’ na neho, ked’ ho dostihne.

Obr. IV.9: Animácia heli.png (rozmerysprite-u: 64x64, trvanie snímku: 0.2).

V triede implementujte verejnú metódu searchAndDestroy(),ktorá spustí prenasledovanie hráca. Pohyb helikoptéry smerom khrácovi pri pustenom prenasledovaní realizujte v metóde vytvorenejpre akciu Invoke. Zabezpecte, aby sa energia hráca znížila o 1, ked’sa s helikoptérou stretne. Pre animáciu helikoptéry použite obrázokheli.png (Obr. IV.9).

Pri tejto úlohe neprekrývajte metódu addedToScene() v triedeHelicopter! Porozmýšl’ajte, kde je vhodnejšie miesto pre napláno-vanie akcie.

Pre získanie referencie na objekt hrácasi prezrite dostupné metódy na objektehernej scény. Hrác je typu Playera má meno Player. Pre overenie, cije helikoptéra v kolízii (dotýka sa)s hrácom, použite vhodnú metódudostupnú na objekte aktéra.

Doplnujúce zdroje• Java Tutoriál: Dedicnost’

http://docs.oracle.com/javase/tutorial/java/concepts/inheritance.html

• Java Tutoriál: Generické typyhttps://docs.oracle.com/javase/tutorial/java/generics/types.html

• Java Tutoriál: Ohranicené typové parametrehttps://docs.oracle.com/javase/tutorial/java/generics/bounded.html

• Java Tutoriál: Referencie na metódyhttps://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

Page 44: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav
Page 45: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

VLet’s Have an Agreement(A.k.a. Let’s rewrite all the things!)

MOTIVÁCIA

Kadet! Od získania hodnosti Trainee t’a delí už len posledná tréningová misia. Jej zvládnutie je pre tvojeprežitie vo svete OOP vel’mi dôležité! Najskôr ti ukážeme, ako sa pripravit’ na prácu bez inšpektora. A - coje mimoriadne dôležité - dostaneme sa k d’alšej stránke polymorfizmu, ktorou je spôsob, ako sa dá s urcitouskupinou typov objektov dohodnút’, ak ich naucíš rozumiet’ urcitému rozhraniu.

V dnešnej misii pre teba náš taktický a strategický tím pripravil dva ciele zamerané na princípy OOP ajeden praktický ciel’, ktorým je refaktorizácia. Všetci dúfame, že v nej preukážeš svoje schopnosti, ktoré sizískal pocas tréningu a budeš tak pripravený na operácie v teréne.

Vel’a št’astia pri zdolávaní ciel’ov! Z velitel’ského mostíka zdraví Manager.

C IELE

1. Porozumiet’ rozhraniam a precvicit’ si ich implementáciu a využitiev d’alšom kóde.

2. Porozumiet’ princípu polymorfizmu a jeho dôsledkom.

3. Precvicit’ si refaktorizáciu kódu.

Krok 1: Lather, Rinse, Repeat

Urcite ste už zaregistrovali, že na overenie správnosti postupu pririešení misií potrebujete opakovat’ cím d’alej tým viac operácií pospustení aplikácie: povytvárat’ potrebné objekty a prepojenia medzinimi, kontrolovat’ správanie po volaní metód. Okrem zdlhavosticelého postupu hrozí aj to, že v reálnom svete bez inšpektora sa budeteorientovat’ s problémami. S ciel’om vyhnút’ sa tejto situácií terazpredstavíme spôsob, ako scenáre pre testovanie misie vytvárat’ priamov kóde.

Page 46: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

38 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 1.1

V balíku sk.tuke.kpi.oop.game vytvorte triedu Gameplay,ktorá bude dedit’ od triedy Scenario dostupnej v hernej knižnicia prekryte jej abstraktnú metódu setupPlay(Scene).

Rámec postavený nad knižnicou GameLib, ktorú v projekte použí-vame, vyhl’adá pri spustení aplikácie implementáciu triedy Sce-

nario a zaregistruje ju ako tzv. listener (resp. event handler1) na scéne. 1 https://en.wikipedia.org/wiki/Event-driven_programming#Event_handlers

Pripravená metóda setupPlay() je zavolaná hned’ po tom, ako je vscéne inicializovaná mapa a aktéri v nej definovaní - zatial’ je to lenpostava hráca (Player). V tejto metóde máme ale možnost’ vkladat’do scény d’alších aktérov a plánovat’ akcie, ktoré budú vykonávat’. Toznamená, že môžeme písat’ scenár.

Úloha 1.2

V scenári pridajte do scény reaktor a zapnite ho.Pre pridanie nového aktéra do scény potrebujete vytvorit’ (alebo

už mat’ k dispozícii) inštanciu daného aktéra a pridat’ ho do scényna nejakú pozíciu (t.j. definovat’ umiestnenie l’avého dolného rohuanimácie aktéra voci l’avému dolnému rohu mapy scény).

Pridanie a zapnutie reaktora teda môže byt’ zapísané takto:

1 Reactor reactor = new Reactor();

2 scene.addActor(reactor, 64, 64);

3 reactor.turnOn();

Implementáciu si overte spustením aplikácie. Reaktor by mal byt’hned’ po štarte umiestnený na danej pozícií a mal by byt’ zapnutý.

Úloha 1.3

Využite znacky (angl. markers) v mape na umiestnovanie aktérov napreddefinované pozície.

Mapa scény, ktorú používame, obsahuje niekol’ko znaciek, ktorémôžu ul’ahcit’ umiestnovanie aktérov. Tieto znacky sú typu Map-

Marker a je ich možné získat’ z mapy scény metódou getMark-

ers():

1 Map<String, MapMarker> markers = scene.getMap().getMarkers();

Typ Map (java.util.Map<K, V>)2 reprezentuje údajovú štruk- 2 https://docs.oracle.com/javase/10/docs/api/java/util/Map.html

Page 47: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

LET ’S HAVE AN AGREEMENT 39

túru zobrazenie obsahujúcu záznamy pozostávajúce z kl’úca (key) typuK a hodnoty (value) typu V. V uvedenom prípade toto zobrazenie ob-sahuje kl’úce definované ret’azcami (String) s názvami jednotlivýchznaciek, ku ktorým sú priradené dané znacky (MapMarker).

Mapa scény obsahuje niekol’ko takýchto znaciek, ktorých mená aumiestnenie sú zobrazené na Obr. V.1.

[0,0]x (352 px)

y (4

32 p

x)

Obr. V.1: MapMarker objekty v mapescény.

Umiestnenie reaktora do scény teda môžeme pomocou znaciekprepísat’ takto:

1 // ziskanie referencie na marker nazvany "reactor-area-1"

2 MapMarker reactorArea1 = markers.get("reactor-area-1");

3

4 //umiestnenie reaktora na poziciu markera

5 scene.addActor(reactor, reactorArea1.getPosX(), reactorArea1.getPosY());

Úloha 1.4

Pridajte do scény chladic a zapnite ho 5 sekúnd po spustení scény.Akciu, ktorou je možné zapnút’ chladic, už poznáte z minulého

cvicenia. V knižnici je dostupná aj akcia Wait, ktorá v konštruktoreakceptuje dlžku trvania cakania (v sekundách). Avšak, pre riešenieúlohy potrebujeme pridat’ akciu zapnutia chladica za akciu cakania.

Page 48: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

40 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Za týmto úcelom vieme použit’ d’alšiu akciu z knižnice - ActionSe-quence, ktorá v konštruktore akceptuje akcie, ktoré bude vykonávat’sekvencne, jednu po druhej.

1 new ActionSequence<>(

2 new Wait<>(5),

3 // akcia pre zapnutie chladica

4 );

Úloha 1.5

Pomocou existujúcich akcií zapíšte scenár pre opravu prehriatehoreaktora kladivom v momente, ked’ teplota reaktora dosiahne hod-notu 3000 stupnov.

Pri riešení tejto úlohy je potrebné akciou zavolat’ metódu repair-

With() na reaktore. Táto metóda však ocakáva jeden argument -kladivo - a teda ju nie je možné odovzdat’ vo forme referencie nametódu do akcie Invoke (nebude sediet’ typovo).

Akcia Invoke však rovnako ako referenciu na bezparametrickúvoid metódu akceptuje aj jej ekvivalent: metódu zapísanú na miestevo forme lambda výrazu3. 3 https://en.wikipedia.org/

wiki/Anonymous_function#Java

1 new Invoke<>(() -> {

2 reactor.repairWith(hammer);

3 });

Lambda výrazy je možné použit’ všade tam, kde sa ocakáva objekttypu rozhrania s práve jednou abstraktnou metódou - tzv. funkcionálnerozhranie4. Namiesto toho, aby sme museli implementovat’ celú triedu

4 https://docs.oracle.com/javase/10/docs/api/java/lang/FunctionalInterface.htmls jednou metódou z toho rozhrania, vieme využit’ lambda výraz.

Lambda výraz teda predstavuje implementáciu tej jednej abstraktnejmetódy a signatúra lambda výrazu (typy parametrov a návratovejhodnoty) musí súhlasit’ so signatúrou metódy v rozhraní.

Akcia Invoke ocakáva ako argument konštruktora objekt typuRunnable5, co je práve rozhranie s jednou metódou void run().

5 https://docs.oracle.com/javase/10/docs/api/java/lang/Runnable.htmlPozastavte sa pri syntaxi lambdavýrazov a ich podobnosti s doterazpoužívanými referenciami na metódy.Telo lambda výrazu nie je volané na mi-este jeho zápisu, ale až v momente, ked’sa ho rozhodne zavolat’ objekt, ktorý nadanú lambdu dostane referenciu.

Pre riešenie druhej casti úlohy (detekcia momentu, kedy teplotareaktora dosiahne danú teplotu) môžeme zas využit’ existujúcu akciuWhen. Prvým argumentom konštruktora akcie When je tzv. predikát- funkcia (lambda výraz) so signatúrou boolean test(Action

action), ktorá v parametri dostane testovanú akciu a má vrátit’boolovskú hodnotu. Predikát sa testuje neustále od momentu napláno-vania akcie When. V momente, ked’ prvýkrát vráti true, akcia defino-vaná v druhom argumente jeho konštruktora bude vykonaná. 6 6 Dokumentácia k akcii When je na

stránke http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/actions/When.html.

Page 49: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

LET ’S HAVE AN AGREEMENT 41

Zápis akcie When v kontexte, kde máme k dispozícií objekty reak-tora a kladiva, teda môže vyzerat’ nasledovne:

1 new When<>(

2 (action) -> {

3 return reactor.getTemperature() >= 3000;

4 },

5 new Invoke<>(() -> {

6 reactor.repairWith(hammer)

7 })

8 ).scheduleOn(reactor);

A ked’že telá oboch metód zapísaných v lambdách pozostávajú lenz jedného výrazu, môžeme zápis skrátit’ do nasledovnej ekvivalentnejpodoby:

1 new When<>(

2 action -> reactor.getTemperature() >= 3000,

3 new Invoke<>(() -> reactor.repairWith(hammer))

4 ).scheduleOn(reactor);

Úloha 1.6

Navrhnite vlastný scenár, ktorým namodelujete správanie niekol’kýchnavzájom prepojených aktérov.

Zápisom rôznych prípadov použitia existujúcich aktérov sa snažteminimalizovat’ použitie inšpektora. Aj pri nasledujúcich úlohách využívajte

možnosti zapísat’ použitie aktérovdo scenára. Scenár clente na metódymodelujúce jednotlivé prípady použitia.V metóde setupPlay() potom lenuved’te, ktorú metódu chcete použit’.Krok 2: Switchable

Doteraz sme vedeli ovládat’ vypínacom len jeden typ zariadení (ob-jektov). Tentokrát sa však pokúsite "prehovorit’" a "dohodnút’" aj sd’alšími objektami, aby sa dali ovládat’. Všetko je len otázkou, akúdohodu vo forme rozhrania im ponúknete.

Úloha 2.1

V balíku sk.tuke.kpi.oop.game vytvorte rozhranie Switchable.Signatúry metód v tomto rozhraní a ich význam je nasledovný:

• void turnOn() - metóda zapne ovládané zariadenie

• void turnOff() - metóda vypne ovládané zariadenie

Page 50: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

42 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Light DefectiveLight

Cooler SmartCooler

<<interface>>Switchable

Reactor

PowerSwitch

Obr. V.2: Vzt’ah tried k rozhraniuSwitchable.

• boolean isOn() - metóda vráti hodnotu, ktorá reprezentujestav zariadenia (true - zariadenie je zapnuté, false - zariadenie jevypnuté)

Úloha 2.2

pravte triedu Reactor tak, aby implementovala rozhranie Switch-able.

Metódy, ktoré majú byt’ súcast’ou rozhrania, už v triede máte.Správanie metódy isOn() máte ale implementované metódou is-

Running(). Použite refaktorizáciu na premenovanie tejto metódy.

Úloha 2.3

Premenujte triedu Controller na PowerSwitch. Nech reprezentujevypínac, ktorý vie zapínat’ a vypínat’ akékol’vek zariadenia implemen-tujúce rozhranie Switchable.

Pri premenovaní triedy využite možnosti refaktorizácie vo vývo-jovom prostredí.

Upravte implementáciu triedy PowerSwitch tak, aby mala nasle-dovné verejné metódy:

• getDevice() - poskytuje referenciu na pripojené zariadenie

• switchOn() - zapína pripojené zariadenie

• switchOff() - vypína pripojené zariadenie

Pre grafické odlíšenie vypínaca vo vypnutej polohe (ked’ je pripo-jené zariadenie vypnuté) môžete využit’ metódu setTint() na jehoanimácii, ktorá jej pridá zafarbenie podl’a definovanej farby. Naprík-lad použitím sivej farby sa utlmí farebnost’ animácie:

1 getAnimation().setTint(Color.GRAY);

Page 51: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

LET ’S HAVE AN AGREEMENT 43

Zafarbenie zrušíte aplikovaním bielej farby.

Úloha 2.4

Overte správnost’ svojej implementácie vytvorením inštancie reaktoraa inštancie triedy PowerSwitch, pomocou ktorej budete vediet’reaktor zapínat’ a vypínat’ (Obr. V.3).

Obr. V.3: Reaktor zapnutý pomocouPowerSwitch-a.

Úloha 2.5

Upravte triedy Cooler a Light tak, aby implementovali rozhranieSwitchable.

Pokial’ tieto triedy už majú implementované požadované metódy,pridajte im anotáciu @Override. Ak majú podobné metódy (funkcional-itou), len ich premenujte. Ak však tieto metódy vôbec neexistujú,vytvorte ich.

Úloha 2.6

Overte správnost’ svojej implementácie.Správnost’ overíte tak, že vytvoríte inštancie uvedených tried a pre

každú inštanciu vytvoríte aj príslušný vypínac, pomocou ktorého hobudete vediet’ ovládat’ (Obr. V.4).

Page 52: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

44 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Obr. V.4: Reaktor, svetlo a in-teligentné chladice ovládané pomocouPowerSwitch-ov.

Krok 3: Producer/consumer

Reaktor dokáže v súcasnosti napájat’ len inštancie triedy Light.Vašou úlohou je pripravit’ vhodný "štandard" pre napájanie l’ubovol’nýchzariadení (navrhnút’ vzájomne kompatibilné "zásuvky" a "zástrcky").

<<interface>>EnergyConsumer

Computer

Light

Reactor

Obr. V.5: Vzt’ah tried k rozhraniuEnergyConsumer

Úloha 3.1

V balíku sk.tuke.kpi.oop.game vytvorte rozhranie EnergyCon-sumer.

Rozhranie EnergyConsumer bude mat’ len jednu metódu. Jejsignatúra a význam je nasledovný:

• void setPowered(boolean) - pomocou tejto metódy bude

Page 53: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

LET ’S HAVE AN AGREEMENT 45

výrobca energie oznamovat’ zariadeniam, že energia je, resp. nie jedodávaná.

Úloha 3.2

Upravte triedu Light tak, aby implementovala rozhranie Energy-Consumer.

Úloha 3.3

V triede Reactor vytvorte z metód addLight() a removeLight()metódy addDevice() a removeDevice(), pomocou ktorých budemožné k reaktoru pripojit’ zariadenia implementujúce rozhranieEnergyConsumer.

Úloha 3.4

Overte správnost’ svojej implementácie.Pokial’ ste postupovali správne, výsledná funkcionalita sa výrazne

nezmení - stále bude svetlo jediným spotrebicom, ktorý je možnépripojit’. Tentokrát ho však reaktor nebude vidiet’ ako objekt typuLight, ale ako objekt typu EnergyConsumer.

Úloha 3.5

Upravte triedu Computer tak aby implementovala rozhranie Ener-gyConsumer.

Pocítac bude fungovat’ len v prípade, že je napájaný elektrinou. Vopacnom prípade pracovat’ nebude (pozastaví prehrávanie animácie avýsledky všetkých operácií budú mat’ hodnotu 0).

Úloha 3.6

Upravte reaktor tak, aby mohol napájat’ viacero zariadení.Referencie na objekty týchto zariadení nech sa ukladajú do množiny.

Využite pritom nasledovný kód na jej vytvorenie:

1 // deklaracia clenskej premennej pre mnozinu pripojenych zariadeni

2 private Set<EnergyConsumer> devices;

3

4 // vytvorenie instancie mnoziny v konstruktore

5 // (typovy parameter pre HashSet je odvodeny na zaklade typu premennej devices)

6 devices = new HashSet<>();

Page 54: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

46 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Použitie množiny oproti štandardnémuzoznamu (typ List) zabezpecí, že jednokonkrétne zariadenie nebude k reaktorupripojené viackrát.

Patricne upravte metódy addDevice() a removeDevice() vtriede Reactor. Pre pridanie zariadenia do množiny použite volaniemetódy add() na objekte množiny. Metódu removeDevice() up-ravte na parametrickú, pricom parametrom nech je objekt typu En-

ergyConsumer. Pre odobratie zariadenia z množiny použite volaniemetódy remove(), ktorej v parametri predáte konkrétny objekt, ktorýsa má z množiny odobrat’.

Úloha 3.7

Overte správnost’ svojej implementácie.Ak ste postupovali správne, budete vediet’ k reaktoru tentokrát

pripojit’ nie len inštancie triedy Light, ale aj inštancie triedy Com-

puter (Obr. V.6). Tu sa prejavuje polymorfizmus využitím rozhraní.

Obr. V.6: Reaktorom napájaný pocítac

Krok 4: Useful refactoring

V rámci prípravy na reálny svet je urcite potrebné zamerat’ sa aj naprecvicenie tzv. refaktorizácie, co je vlastne zmena štruktúry už im-plemetovaného kódu. K takým zmenám dochádza casto bud’ po

Page 55: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

LET ’S HAVE AN AGREEMENT 47

zmene požiadaviek, alebo preto, že objavíme v implementácii nejakénedostatky. V tomto prípade pôjde o zovšeobecnenie nástrojov napoužitel’ných aktérov a o otocenie vzt’ahu medzi iniciátorom použitia apoužívaným objektom. Rozhraním rozlíšime aj skupinu aktérov, ktoréje možné opravit’.

Úloha 4.1

Do balíka sk.tuke.kpi.oop.game.tools pridajte rozhranieUsable reprezentujúce použitel’ných aktérov - nástroje.

V rozhraní definujte jednu metódu so signatúrou void use-

With(T actor), kde T reprezentuje typový parameter viazaný7 na 7 Viac o viazaných (angl. bounded)typových parametroch je napísané nastránke https://docs.oracle.com/javase/tutorial/java/generics/bounded.html

podtypy Actor-a. Actor dodaný v parametri metódy useWith()

bude slúžit’ na dodefinovanie kontextu použitia Usable aktéra.

Úloha 4.2

Upravte abstraktnú triedu BreakableTool tak, aby implementovalarozhranie Usable a aby umožnila dodefinovat’ typový parameter vosvojich konkrétnych implementáciách (podtriedach).

Metódu use() z pôvodnej implementácie BreakableTool up-ravte tak, aby prekrývala metódu useWith() z rozhrania Usable.Nezabudnite na anotáciu @Override.

Úloha 4.3

Upravte konkrétne implementácie triedy BreakableTool tak, abyboli kompatibilné s úpravami z predošlej úlohy.

Typovým parametrom pre BreakableTool špecifikujte typ ak-téra, s ktorým môže daný nástroj pracovat’ (ktorý vie opravit’; napr.kladivo vie opravit’ reaktor).

V jednotlivých nástrojoch prekryte implementáciu metódy use-

With() a vykonajte príslušnú opravu.Nezabudnite upravit’ metódy opravy reaktora repairWith()

a extinguishWith(), ktoré teraz premenujte na repair() a ex-tinguish(), ked’že opravu vyvolajú samotné nástroje kladivo, resp.hasiaci prístroj. Pri týchto upravených metódach využite návratovúhodnotu boolean na signalizáciu úspešnosti, resp. neúspešnostipoužitia nástroja.

Úloha 4.4

Pridajte rozhranie Repairable reprezentujúce opravitel’ných aktérov.V rozhraní definujte metódu so signatúrou boolean repair().

Návratová hodnota bude vyjadrovat’ úspešnost’, resp. neúspešnost’

Page 56: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

48 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

opravy.

Úloha 4.5

Upravte triedu Reactor nech implementuje rozhranie Repairable.

Úloha 4.6

Upravte triedu DefectiveLight tak, aby tiež implementovalarozhranie Repairable.

Oprava svetla (svetlo prestane blikat’) však vydrží len 10 sekúnd apotom sa svetlo opät’ pokazí.

Metódy scheduleAction() na scénea scheduleOn() na akcii vracajúobjekt typu Disposable. Zavolaniemetódy dispose() na takomto objektezruší naplánovanie, resp. prerušívykonávanie akcie, ktorá bola volanímdanej schedule* metódy naplánovaná.Možnost’ zrušit’ skôr naplánované akciesa vám zíde pri riešení tejto úlohy.

Úloha 4.7

Vytvorte triedu Wrench pre francúzsky kl’úc, ktorý bude podobne,ako kladivo, použitel’ný na opravu pokazených zariadení - konkrétnezariadenia DefectiveLight.

Nech Wrench rozširuje triedu BreakableTool a má 2 použitia.Pre jeho grafickú reprezentáciu použite obrázok wrench.png (Obr.V.7). Obr. V.7: Animácia wrench.png

(rozmery sprite-u: 16x16)

Doplnujúce úlohy

Úloha A5.1

Vytvorte triedu TimeBomb, ktorá bude predstavovat’ casovanúbombu.

Trieda by mala obsahovat’: Obr. V.8: Animácia bomb.png (rozmerysprite-u: 16x16)

Obr. V.9: Animácia bomb_-activated.png (rozmery sprite-u:16x16)

• parametrický konštruktor, pomocou ktorého nastavíte cas (vsekundách, typ float), ktorý má uplynút’ od aktivácie bombypo jej detonáciu,

• verejnú metódu activate(), ktorá bude slúžit’ na aktiváciubomby, pri ktorej sa spustí odpocítavanie do výbuchu. Pre ani-máciu bomby pred aktiváciou použite obrázok bomb.png (Obr.V.8). Pri aktivácii nech bomba zacne iskrit’ (použite bomb_acti-vated.png - Obr. V.9).

• verejnú metódu boolean isActivated(), ktorá vráti, ci jebomba aktuálne aktivovaná.

Obr. V.10: Animácia small_-explosion.png (rozmery sprite-u:16x16)

Pri detonácii bomby použite animáciu small_explosion.png

(Obr. V.10). Zabezpecte, aby sa animácia prehrala jedenkrát (použitevhodný PlayMode8 animácie) a objekt potom zmizol z herného sveta 8 Režimy pre prehrávanie animácií sú

zdokumentované na stránke http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/graphics/Animation.PlayMode.html

Page 57: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

LET ’S HAVE AN AGREEMENT 49

(bomba sa rozmetala do vzduchu).Pri implementácii odstránenia aktéra bomby zo scény odporúcame

využit’ akciu When.

Úloha A5.2

Vytvorte triedu ChainBomb, ktorá bude potomkom triedy TimeBomb.Zabezpecte, aby sa pri výbuchu aktivovali všetky bomby typu Chain-

Bomb, ktoré sú vzdialené 50 (a menej) jednotiek od stredu aktuálnejaktivovanej bomby. Pri implementácii dbajte na to, aby

ste neopakovali už implementovanúfunkcionalitu predka. V prípade potrebykód refaktorujte.

Konštruktor triedy ChainBomb bude tiež akceptovat’ v parametricas od aktivácie do detonácie.

Uvedomte si, že každý následný výbuch môže spôsobit’ d’alšievýbuchy pre dominový efekt: v momente detonácie jednej bomby saaktivujú všetky ešte neaktivované bomby v dosahu.

Pre rádius výbuchu môžete využit’ triedu Ellipse2D.Float

z balíka java.awt.geom a pre docasnú reprezentáciu animácieokolitých aktérov triedu Rectangle2D.Float (z toho istého balíka).Následne je možné použit’ metódu intersects nad útvarom elipsypre zistenie vzájomného prekrytia.

Úloha A5.3

Vytvorte triedu Teleport, ktorou budete modelovat’ teleportovaniehráca medzi dvoma miestami vo svete.

Funkcia teleportu má byt’ nasledovná:

• Ak hrác vojde na teleport A, bude okamžite presunutý na ciel’ovýteleport B. Hrác vojde na teleport až vtedy, ked’ sa bod v stredeanimácie hráca dostane do oblasti definovanej animáciou teleportu.

• Ak bol hrác práve presunutý na teleport A z iného teleportu, neb-ude presunutý na ciel’ový teleport teleportu A pokial’ z celéhopriestoru teleportu A najskôr nevyjde a nevráti sa spät’.

• V prípade, že teleport A nemá pripojený ciel’ový teleport, hrácnebude nikam teleportovaný.

• Teleport A nemôže mat’ ako ciel’ nastavený sám seba (teleport A).

Trieda Teleport by mala obsahovat’:Obr. V.11: Animácia lift.png(rozmery sprite-u: 48x48)• Konštruktor, ktorý umožní prostredníctvom parametra nastavit’

ciel’ový teleport, a ktorý použije obrázok lift.png pre animáciuteleportu.

• Metódy getDestination() a setDestination(TeleportdestinationTeleport), ktorým je možné získat’ referenciu naciel’ový teleport, resp. zmenit’ ciel’ový teleport.

Page 58: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

50 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

• Metódu teleportPlayer(Player player), ktorou ciel’ovýteleport nastaví novú pozíciu hráca pri teleportovaní. Hrác mábyt’ premiestnený tak, aby súradnice stredu ciel’ového teleportu asúradnice stredu hráca boli totožné.

Doplnujúce zdroje• Dokumentácia ku knižnici GameLib

http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/index.html

• Akcie dostupné v knižnici Gamelibhttp://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/

actions/package-summary.html

• Java Tutoriál: What Is an Interface?http://docs.oracle.com/javase/tutorial/java/concepts/interface.html

• Java Tutoriál: The List Interfacehttp://docs.oracle.com/javase/tutorial/collections/interfaces/list.html

• Java Tutoriál: List Implementationshttp://docs.oracle.com/javase/tutorial/collections/implementations/list.html

• Java Tutoriál: Lambda Expressionshttps://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

• Java Tutoriál: Bounded Type Parametershttps://docs.oracle.com/javase/tutorial/java/generics/bounded.html

Page 59: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

VII knew you’d come (Ripley)

MOTIVÁCIA

Nová kolónia na planéte Acheron (LV-426)1 sa už niekol’ko dní nehlási aj napriek tomu, že overenie spojenia1 http://avp.wikia.com/wiki/Acheron_(LV-426)pomocou satelitov bolo úspešné. Obávame sa najhoršieho, pretože satelitné snímky nedetegujú v kolónii

žiadne známky života.Operacné stredisko rozhodlo, že s tvojimi schopnost’ami budeme schopní zostrojit’ na dial’ku ovládaného

androida, ktorý by situáciu mohol zvládnut’. Náš taktický a strategický tím t’a povedie vo vývoji. Misiadostala názov: Ellen.

Aby si si urobil predstavu o vážnosti celej situácie, odporúcame ti zhliadnut’ dokumentárne filmyPrometheus2, Alien3 a Aliens4. 2 Film Prometheus: http://www.imdb.

com/title/tt1446714/?ref_=fn_al_tt_13 Film Alien: http://www.imdb.com/title/tt0078748/?ref_=fn_al_tt_14 Film Aliens: http://www.imdb.com/title/tt0090605/?ref_=fn_al_tt_4

Z operacného strediska zdraví Manager.

C IELE

1. Použit’ statickú metódu main() na spustenie aplikácie.

2. Naucit’ sa vytvárat’ a používat’ vlastný enumeracný typ.

3. Oboznámit’ sa s návrhovým vzorom Observer (listener, callback).

Krok 1: Let’s start from the beginning

Zatial’ ste vo svojom projekte pridávali aktérov do scény bud’ pomocouInšpektora, respektíve ste písali jednoduché scenáre. Odkial’ sa všakvzala samotná scéna alebo Inšpektor? Preco má okno spustenej apliká-cie práve dané rozmery? V tomto kroku si ukážeme, ako vyskladat’celú aplikáciu pekne od zaciatku... od funkcie main, ktorá predstavujevstupný bod Java aplikácií.

Úloha 1.1

V balíku sk.tuke.kpi.oop.game vytvorte triedu Main.

Page 60: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

52 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 1.2

V triede Main vytvorte statickú metódu main() so signatúroumetódy, ktorá v Jave reprezentuje vstupný bod aplikácie.

Metóda, ktorá môže byt’ nastavená ako tá, ktorá sa zavolá prvá pospustení aplikácie, musí mat’ v jazyku Java nasledovnú signatúru:

1 public static void main(String[] args) {

2

3 }

Úloha 1.3

Upravte Gradle konfiguráciu pre spúšt’anie novej main() metódy.V súbore build.gradle.kts upravte hodnotu premennej main-

ClassName v bloku application na plné meno práve vytvorenejtriedy Main obsahujúcej statickú metódu main():

1 application {

2 mainClassName = "sk.tuke.kpi.oop.game.Main"

3 }

Úloha 1.4

V metóde main() vytvorte hernú aplikáciu, pridajte do nej scénu ahru spustite.

K vytvoreniu aplikácie potrebujeme pripravit’ minimálne 3 objekty -konfiguráciu okna, samotnú hru, a scénu, ktorú bude hra zobrazovat’.Fragment kódu VI.1 poskytuje ukážku implementácie so sprievod-nými komentármi.

Úloha 1.5

Zabezpecte, aby sa po stlacení klávesy ESCAPE aplikácia hry ukoncila.V prvom rade, hru vieme korektne z kódu ukoncit’ volaním metódy

stop() nad objektom typu Game, ku ktorému sa dostaneme zo scénypomocou metódy getGame().

Pre získanie objektu triedy Input5, pomocou ktorého vieme praco- 5 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/Input.html

vat’ so vstupnými zariadeniami (napr. klávesnicou), máme na objektescény metódu getInput(). Možností, ako reagovat’ na stlacenieklávesy, máme niekol’ko:

• budeme neustále (napr. v rámci nejakej opakovanej akcie) kon-trolovat’, ci bola stlacená požadovaná klávesa pomocou metódy

Page 61: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

I KNEW YOU ’D COME (RIPLEY) 53

1 public static void main(String[] args) {

2 // nastavenie okna hry: nazov okna a jeho rozmery

3 WindowSetup windowSetup = new WindowSetup("Project Ellen", 800, 600);

4

5 // vytvorenie instancie hernej aplikacie

6 // pouzijeme implementaciu rozhrania \codeinline{Game}

7 // triedou \codeinline{GameApplication}

8 Game game = new GameApplication(windowSetup);

9

10 // vytvorenie sceny pre hru

11 // pouzijeme implementaciu rozhrania \codeinline{Scene}

12 // triedou \codeinline{World}

13 Scene scene = new World("world");

14

15 // pridanie sceny do hry

16 game.addScene(scene);

17

18 // spustenie hry

19 game.start();

20 }

Fragment kódu VI.1: Implementá-cia metódy main(), ktorá slúži akospúšt’ací bod aplikácie.isKeyPressed(), alebo

• nastavíme tzv. callback6 v podobe lambdy odovzdanej metóde 6 https://en.wikipedia.org/wiki/Callback_(computer_programming)

onKeyPressed(), ktorú zavolá knižnica vždy vtedy, ked’ dôjde kstlaceniu nejakej klávesy.

Využijeme druhú možnost’ pomocou callback-u. Riešenie môževyzerat’ nasledovne:

1 scene.getInput().onKeyPressed(key -> {

2 if (key == Input.Key.ESCAPE) {

3 game.stop();

4 }

5 });

Úloha 1.6

V novom balíku sk.tuke.kpi.oop.game.scenarios si pripravtenovú triedu pre písanie scenára.

Triedu nazvite napríklad FirstSteps.

Page 62: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

54 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Tentoraz bude trieda scenára priamo implementovat’ rozhranieSceneListener7 z knižnice. V triede prekryte metódu sceneIni-

7 Rozhranie SceneListenerje zdokumentované na stránkehttp://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/SceneListener.html

tialized() z rozhrania SceneListener - do tejto metódy budetecoskoro písat’ scenár. Casti scenára môžete tak ako predtým organizo-vat’ do samostatných metód.

Triedu Gameplay, kam ste písali scenár v predošlých cviceniach,presunte do balíka scenarios a premenujte na TrainingGameplay. Abstraktná trieda Scenario, od ktorej

dedila trieda Gameplay, tiež implemen-tovala rozhranie SceneListener.

Úloha 1.7

Pridajte triedu pre scenár ako listener na scénu vytvorenú v metódemain().

V metóde main() triedy Main vytvorte inštanciu triedy scenára apridajte ju pomocou metódy addListener()8 k vytvorenej scéne.

8 Dokumentácia je dostupná nastránke http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/Scene.html#addListener(sk.tuke.kpi.gamelib.SceneListener)

Všetky úpravy týkajúce sa scény musíte vykonat’ pred zavolanímmetódy game.start()!

Úloha 1.8

Overte správnost’ implementácie.Ak ste postupovali správne, po spustení aplikácie prostredníctvom

Gradle úlohy run (ten istý spôsob spustenia, aký ste používali doteraz)sa zobrazí prázdne okno s návom, ktorý ste zadali v konštruktoreWindowSetup.

Všimnite si, že okno Inšpektora sa už nezobrazí.

Nástroj Inšpektor by ste už nemali potrebovat’, ked’že ho viemeviac ako dostatocne nahradit’ scenárom a debuggerom vo vývojovomprostredí. Ak by ste však predsa z nejakého dôvodu chceli mat’ In-špektora ešte k dispozícii, je potrebné pri vytváraní hry zaobalit’ bežnúscénu do InspectableScene, ktorá slúži ako jej dekorátor9 - rozšíri 9 https://sourcemaking.com/

design_patterns/decoratorju o funkcionalitu Inšpektora. Túto novú scénu je potom potrebnépoužit’ v hre:

1 Scene scene = new InspectableScene(new World("world"), List.of("sk.tuke.kpi"));

2 game.addScene(scene);

Druhým argumentom konštruktora InspectableScene je zoz-nam názvov balíkov, v ktorých má Inšpektor hl’adat’ triedy, ktorébude zobrazovat’ (musia byt’ anotované anotáciou @Inspectable).Použitý zápis využíva statickú metódu of()10, ktorá je tzv. factory

10 https://docs.oracle.com/javase/9/docs/api/java/util/List.html#of-E...-

metódou11 na rozhraní kolekcie zoznamu List, ktorá skonštruuje ne- 11 https://sourcemaking.com/design_patterns/factory_method

Page 63: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

I KNEW YOU ’D COME (RIPLEY) 55

menný zoznam obsahujúci uvedené elementy (v tomto prípade jedenret’azec "sk.tuke.kpi").

Krok 2: Ripley is back!

Postava základného hráca, ktorú ste doteraz mali k dispozícii, sa užv novej scéne nezobrazuje. Namiesto neho si však vytvoríte vlastnúhlavnú postavu hry: Ripleyovú. A postupne ju budete ucit’.

<<abstract>>AbstractActor

<<interface>>ActorRipley

Obr. VI.1: Trieda Ripley implementu-júca rozhranie Actor

Úloha 2.1

V novom balíku sk.tuke.kpi.oop.game.characters vytvortetriedu Ripley, ktorá bude dedit’ od triedy AbstractActor.

V triede vytvorte bezparametrický konštruktor v ktorom:

• zavolajte konštruktor rodica a odovzdajte mu meno aktéra akoargument: Ellen.

• nastavte animáciu s názvom player.png (Obr. VI.2) a režimomprehrávania LOOP_PINGPONG. Obr. VI.2: Animácia player.png

(rozmery sprite-u: 32x32, trvaniesnímku: 0.1). Na prvý pohl’ad by samohlo zdat’, že sa jedná o muža, alenedajte sa zmiast’ - je to naozaj EllenRipley.Úloha 2.2

V pripravenom scenári vytvorte inštanciu Ripleyovej a umiestnite ju doscény.

Vloženie do scény realizujte pomocou metódy addActor(Actor,

int, int), ktorou môžete priamo definovat’ aj pozíciu, kde budeRipleyová umiestnená. Štandardne sa bude pozícia [0, 0] nachádzat’ vstrede okna.

Úloha 2.3

Overte správnost’ svojej implementácie.V prípade správnej implementácie sa vám po spustení hry zobrazí

prázdny svet, v ktorom sa objaví Ripleyová na definovanej pozícii (Obr.VI.3).

Page 64: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

56 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Obr. VI.3: Ripleyová nervózne prešl’apu-júca na mieste.

Krok 3: First Steps with Ellen Ripley

Aktuálne vie Ripleyová iba nervózne prešl’apovat’ na mieste. To savšak vel’mi skoro zmení.

Move

<<enum>>Direction

<<interface>>Movable

Ripley

<<interface>>Actor

<<interface>>Action

Obr. VI.4: Implementácia pohybu preaktérov.

Úloha 3.1

Vytvorte enumeracný typ12 Direction, v ktorom definujte 4 možné 12 Viac o enumeracných typoch je nastránke https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

smery pohybu aktéra.Definujte 4 smery: NORTH, EAST, SOUTH a WEST.V enumeracnom type Direction pridajte privátne a finálne

celocíselné clenské premenné dx a dy, ktoré budú reprezentovat’zmeny polohy v osiach x a y potrebné pre pohyb v danom smere.Premenné inicializujte v konštruktore Direction(int dx, int

dy) a pridajte im getter metódy. Definícia smeru NORTH bude zapísanáako NORTH(0, 1).

Úloha 3.2

Do enumerácie Direction pridajte smer NONE nereprezentujúcižiaden konkrétny smer pohybu.

Hodnoty dx a dy smeru NONE nastavte na 0.

Page 65: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

I KNEW YOU ’D COME (RIPLEY) 57

Smer NONE budeme využívat’ v zmysle návrhového vzoru NullObject13. 13 Viac o návrhovom vzore Null Object

je na adrese https://sourcemaking.com/design_patterns/null_objectÚloha 3.3

Do enumerácie Direction pridajte metódu float getAngle(),ktorá vráti uhol (v stupnoch) zodpovedajúci danému smeru.

Úloha 3.4

Vytvorte rozhranie Movable, ktoré bude reprezentovat’ aktérov, ktorísa môžu pohybovat’.

Movable bude rozširovat’ rozhranie Actor a bude obsahovat’ tietometódy:

• int getSpeed() pre získanie rýchlosti pohybu aktéra.

• void startedMoving(Direction direction) ako listenerpre udalost’ zacatia pohybu v smere direction.

• void stoppedMoving() ako listener pre udalost’ zastaveniapohybu.

Metódam startedMoving() a stoppedMoving() pridajte vrámci rozhrania prázdnu default implementáciu, aby ich nebolo nutnéimplementovat’ v každom Movable aktérovi, ak to daný aktér nebudevyžadovat’.

Default implementácia metódy stoppedMoving() v rozhraníbude vyzerat’ takto:

1 default void stoppedMoving() {}

Úloha 3.5

Upravte triedu Ripley tak, aby implementovala rozhranie Movable.Nastavte Ripleyovej rýchlost’ napríklad na hodnotu 2. V metóde

startedMoving() otocte animáciu v smere pohybu a spustite ju. Vmetóde stoppedMoving animáciu pozastavte.

Úloha 3.6

V balíku sk.tuke.kpi.oop.game.actions vytvorte triedu preakciu Move, ktorá bude reprezentovat’ pohyb aktéra v urcitom smereza urcitú dobu.

Page 66: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

58 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Pri implementácií použite priamo rozhranie Action z balíkaknižnice sk.tuke.kpi.gamelib.actions. Akcia bude mat’vlastný typový parameter viazaný na typ Movable.

Jej konštruktor bude mat’ parametre urcujúce smer pohybu atrvanie pohybu v sekundách.

1 public Move(Direction direction, float duration) {

2 // implementacia konstruktora akcie

3 }

Pridajte aj pret’ažený konštruktor len s jedným parametrom typu Di-

rection. V tomto prípade budeme cas pohybu považovat’ za nulový,co bude znamenat’ pohyb aktéra len o jeden krok bez opakovania.

Úloha 3.7

V akcii Move implementujte metódy getActor(), setActor(),isDone() a reset() z rozhrania Action.

Význam jednotlivých metód je nasledovný:

• getActor() a setActor() slúžia ako getter a setter pre aktéra,ktorý vykonáva danú akciu. Nastavuje ho scéna pri naplánovaníakcie.

• isDone() reprezentuje ukoncenie akcie. Po inicializovaní akcieby táto metóda mala vrátit’ false, aby metóda execute() bolaaspon raz zavolaná. Ked’že akcia Move bude môct’ nejaký castrvat’, true táto metóda vráti, až ked’ uplynie jej cas. Zmenu stavubudete riešit’ v d’alšej úlohe.

• reset() metóda obnoví stav akcie (s výnimkou nastavenéhoaktéra) do pôvodného stavu po vytvorení akcie.

Úloha 3.8

V akcii Move implementujte metódu execute() z rozhrania Action.V rámci metódy execute() implementujte nasledovné:

• V prípade, že je metóda volaná prvýkrát, zavolajte metódu start-

edMoving() na aktérovi vykonávajúcom akciu.

• Aktualizujte pozíciu aktéra vzhl’adom na smer pohybu a jehorýchlost’ (získate ju metódou getSpeed()).

• Ak celkový cas behu akcie prekrocí, alebo sa rovná casu defino-vanému pri vytváraní inštancie akcie, ukoncite akciu. To znamená,

Page 67: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

I KNEW YOU ’D COME (RIPLEY) 59

že od toho momentu musí metóda isDone() vrátit’ hodnotu true.Nezabudnite zavolat’ metódu stoppedMoving() na pohybujú-com sa aktérovi.

Cas, ktorý uplynul medzi dvoma vola-niami metódy execute(), dostanetev parametri deltaTime metódyexecute().

Pre vyhodnotenie zhody uplynutéhocasu akcie voci definovanému trvaniumyslite na to, že v binárnej reprezentáciídesatinných císel dochádza k malým od-chýlkam, kvôli ktorým dve císla môžubyt’ takmer zhodné, no nemusia byt’úplne zhodné. Vyhodnotenie rovnostipreto realizujte ako porovnanie absolút-nej hodnoty rozdielu porovnávanýchcísel voci císlu dostatocne blízkemu 0,napr. 1e-5.

Úloha 3.9

Overte správnost’ implementácie pohybu naplánovaním akcie Movepre Ripleyovú v pripravenom scenári.

Pri správnej implementácii by sa Ripleyová mala posunút’ v defino-vanom smere pocas definovanej doby, pricom jej animácia by sa malaprehrávat’ len pri pohybe.

Krok 4: Mission Controller

Ripleyová sa už teda vie pohybovat’, zatial’ ale len podl’a vopredpripraveného scenára. To však zoci-voci nepriatel’om nebude postaco-vat’ - potrebujeme nieco flexibilnejšie. V tomto kroku si ukážeme, akonavigovat’ Ripleyovú v reálnom case pomocou klávesnice.

KeyboardController

Move

<<enum>>Direction

<<interface>>Movable

KeyboardListener

Obr. VI.5: Controller pre ovládaniepohybu aktérov.

Úloha 4.1

Vytvorte triedu KeyboardController, ktorá bude reprezentovat’ovládac pohybu aktéra pomocou klávesnice.

Trieda KeyboardController nech implementuje rozhranieKeyboardListener z hernej knižnice. Toto rozhranie obsahujemetódy, ktoré v štýle návrhového vzoru observer14 slúžia ako listener 14 https://sourcemaking.com/

design_patterns/observerfunkcie volané knižnicou pri zmene stlacených kláves na klávesnici.Implementáciou týchto metód teda vieme na stlácané (a uvol’nené)klávesy reagovat’.

V triede vytvorte konštruktor, ktorý vo svojom parametri akceptujereferenciu na Movable aktéra, ktorého pohyb bude ovládat’.

Page 68: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

60 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 4.2

Vytvorte clenskú premennú pre zobrazenie (Map), ktorým bude možné"prekladat’" jednu zo štyroch smerových kláves (šípky hore, vl’avo,dole vpravo) na jeden zo štyroch základných smerov enumerácieDirection.

Typ clenskej premennej bude Map<Input.Key, Direction> -teda zobrazenie, kde kl’úcom bude klávesa a hodnotou smer pohybu.Použitím metódy get(), ktorá akceptuje kl’úc (Input.Key), takzískame príslušnú hodnotu (Direction). Alternatívou takéhoto postupu prekladu

klávesy na smer by bolo bud’ vetveniepomocou if a else, alebo switch.Použitie zobrazenia je ale viac objektovýprístup, preto použijeme tento.

Zobrazenie však musí byt’ "naplnené" kombináciami klávesa-smer.Túto inicializáciu viete vykonat’ bud’ pomocou metódy put() nad ob-jektom zobrazenia, alebo pomocou factory metódy Map.ofEntries(),ktorej odovzdáte 4 parametre vytvorené volaním funkcie Map.entry()s dvojicami hodnôt klávesy a smeru pohybu:

1 private Map<Input.Key, Direction> keyDirectionMap = Map.ofEntries(

2 Map.entry(Input.Key.UP, Direction.NORTH),

3 // dalsie zaznamy zobrazenia prekladu ...

4 );

Úloha 4.3

Pridajte clenskú premennú na uchovanie referencie na akciu pohybuMove.

V tejto clenskej premennej budete udržiavat’ referenciu na poslednevytvorenú akciu Move, aby ste ju vedeli zrušit’ v prípade, že sa smerpohybu aktéra zmení.

Úloha 4.4

Upravte implementáciu Move tak, aby ste na nej mali dostupnúverejnú metódu stop(), ktorou budete vediet’ kedykol’vek zastavit’prebiehajúci pohyb.

Nezabudnite, že pre ukoncenie akcie je potrebné zmenit’ jej stavvrátený metódou isDone() na true a ked’že pracujeme s Movableaktérom, je potrebné zavolat’ jeho metódu stoppedMoving()! Refaktorizujte existujúcu implementáciu

tak, aby ste sa vyhli duplikovaniufunkcionality.

Úloha 4.5

Implementujte metódu keyPressed() z rozhrania Keyboard-Listener, ktorá reprezentuje listener udalosti stlacenia klávesy na

Page 69: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

I KNEW YOU ’D COME (RIPLEY) 61

klávesnici.V metóde skontrolujte, ci stlacená klávesa je jedna zo štyroch

smerových kláves. Ak áno, naplánujte pohyb ovládaného aktéra vzodpovedajúcom smere na maximálny možný cas. Nezabudnite siuložit’ referenciu na vytvorenú akciu.

Tu viete využit’ metódu containsKey() nad objektom Map-y,kam ste ukladali preklad kláves na smery pre overenie stlacenejklávesy.

Myslite aj na to, že predchádzajúcuakciu (ak existuje), treba zastavit’volaním jej metódy stop() predvytvorením novej akcie pohybu.

Úloha 4.6

Implementujte metódu keyReleased() z rozhrania Keyboard-Listener, ktorá reprezentuje listener udalosti uvol’nenia klávesy naklávesnici.

Postup pri tejto metóde bude analogický: skontrolujte, ci sa jedná oklávesu, ktorá nás zaujíma a ak áno, zastavte prebiehajúci pohyb (aknejaký prebieha).

Upravte implementáciu metódkeyPressed() a keyReleased() tak,aby ste sa vyhli duplikácii funkcionality.

Úloha 4.7

V rámci scenára vytvorte inštanciu vytvoreného KeyboardCon-troller-a, odovzdajte mu referenciu na Ripleyovú a nastavte ho akolistener pre spracovanie vstupu.

Registrácia listenera vstupu sa realizuje metódu registerLis-

tener() na objekte Input, ktorý zo scény získate metódou get-

Input().

Úloha 4.8

Overte správnost’ implementácie: Ripleyovej pohyb by sa mala dat’ovládat’ pomocou klávesnice.

Doplnujúce úlohyV rámci doplnujúcich úloh rozšírite implementáciu pohybu aj nadiagonálne smery.

Úloha A6.1

Rozšírte implementáciu Direction o diagonálne smery pohybu.K hodnotám enumeracného typu pridajte 4 diagonálne smery

pohybu.

Úloha A6.2

Do enumeracného typu Direction pridajte metódu combine(), po-

Page 70: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

62 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

mocou ktorej bude možné skombinovat’ l’ubovol’né 2 smery pohybudo jedného.

Metóda nech má signatúru public Direction combine(Direction

other). Nech metóda vráti smer NONE v prípade, že nebude možnénájst’ správny skombinovaný smer (co by sa však za normálnychokolností stat’ nemalo). Pri riešení tejto úlohy sa vyhnite

použitiu príkazu switch, aleborozsiahlemu vetveniu pomocou if-else. Využite metódu values()(Direction.values()) dostupnúna každom enumeracnom type, ktorávráti pole všetkých možných hodnôtenumerácie.

Úloha A6.3

Upravte implementáciu KeyboardController tak, aby bolo možnéaktérov ovládat’ aj v diagonálnych smeroch pohybu, kedy sú stlacené2 smerové klávesy (prípadne aj viac...).

Pre riešenie tejto úlohy si budete v rámci KeyboardController-auchovávat’ množinu (Set) základných smerov pohybu, ktoré zod-povedajú všetkým práve stlaceným smerovým klávesám. Pre urcenievýsledného smeru pohybu využite metódu combine() na typeDirection, ktorou smery postupne skombinujete do jedného.

Overte svoju implementáciu vyskúšaním ovládania Ripleyovej vrôznych smeroch.

Doplnujúce zdroje• Who is Ellen Ripley

http://en.wikipedia.org/wiki/Ellen_Ripley

• Softvérový rámec GameLibhttps://kurzy.kpi.fei.tuke.sk/oop/pages/gamelib.html

JavaDochttp://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/index.html

• Callback: odovzdávanie vykonatel’ného kódu ako argument volania funkcie, wikipedia.orghttps://en.wikipedia.org/wiki/Callback_(computer_programming)

• Java Tutorial: Enumeracný typhttps://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

• Návrhový vzor Observerhttps://sourcemaking.com/design_patterns/observer

• Návrhový vzor Null Objecthttps://sourcemaking.com/design_patterns/null_object

• Návrhový vzor Factory Methodhttps://sourcemaking.com/design_patterns/factory_method

Page 71: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

VIIUsable Items

MOTIVÁCIA

Kolonisti z planéty Acheron (LV-426) používali pri kolonizovaní planéty mnoho prístrojov a špeciálnychzariadení. Je možné predpokladat’, že mnohé z nich budú ešte stále plne alebo aspon ciastocne funkcné.Preto by k úspechu akcie pocas tvojho výsadku na planéte mohlo pomôct’ ich zvládnutie.

Technickí odborníci z nášho strategického a taktického tímu t’a teda dnes naucia tieto prístroje a zariade-nia ovládat’ a pomôct’ tak Ripleyovej ich vhodne používat’.

Z operacného strediska zdraví Manager.

C IELE

1. Použit’ marker interface na odlíšenie podskupiny objektov.

2. Precvicit’ si generické programovanie.

3. Naucit’ sa použit’ návrhový vzor Iterator.

4. Naucit’ sa vyvolávat’ a spracovávat’ výnimky.

Krok 1: Useful Rubbish

Podl’a obrazu z niektorých funkcných kamier, prebiehali v priestorochkolónie t’ažké boje, po ktorých zostalo v miestnostiach množstvorozhádzaných predmetov. Také lekárnicky alebo zásobníky by samohli celkom hodit’...

<<abstract>>AbstractActorAmmo

Energy <<interface>>Usable

Obr. VII.1: Triedy Energy a Ammoimplementujúce rozhranie Usable.

Page 72: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

64 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 1.1

Pomocou refaktorizácie premenujte balík sk.tuke.kpi.oop.game.toolsna sk.tuke.kpi.oop.game.items.

V rámci tohto kroku zacneme do projektu pridávat’ d’alšie pred-mety, ktoré môžu byt’ pre Ripleyovú užitocné. Ked’že niektoré z týchtopredmetov budú zároven nástrojmi, balík tools zovšeobecníme naitems.

Úloha 1.2

V balíku sk.tuke.kpi.oop.game.items vytvorte triedu Energy,ktorá bude potomkom triedy AbstractActor a bude implemento-vat’ rozhranie Usable.

Trieda Energy bude reprezentovat’ lekárnicku, ktorá vždy povzbudíRipleyovej náladu a doplní jej energiu na 100%. Túto funkcionalituvšak budete implementovat’ neskôr.

Ako animáciu pre reprezentáciu lekárnicky použite súbor en-ergy.png (Obr. VII.2). Obr. VII.2: Animácia energy.png

(rozmery spritu: 16x16).

Úloha 1.3

Upravte triedu Ripley tak, aby ste mali k dispozícií get a set metódypre stav energie.

Energia Ripleyovej bude reprezentovaná celým císlom. Využívat’budeme rozsah 0 - 100 v zmysle percent zostávajúcej energie. Pocia-tocná hodnota energie nech je 100.

Úloha 1.4

V metóde useWith() triedy Energy implementujte doplnenieenergie Ripleyovej na 100%.

Zabezpecte, aby po zmene stavu energie Ripleyovej bola lekárnickaodstránená zo scény. Ak Ripleyová bude mat’ plnú energiu, k "použi-tiu" lekárnicky nedôjde.

Úloha 1.5

V balíku pre akcie vytvorte novú akciu Use rozširujúcu triedu Ab-

stractAction.Akcia Use bude mat’ konštruktor s jedným parametrom, ktorý

bude typu Usable aktéra použitel’ného s nejakým aktérom. Actor, prektorého sa daná Use akcia naplánuje, bude, samozrejme, dostupný zmetódy getActor() (resp. nastavený volaním metódy setActor()

scénou).

Page 73: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

USABLE ITEMS 65

Napríklad pri zámere použit’ lekárnicku s Ripleyovou (na doplneniejej energie), co by bolo reprezentované volaním energy.useWith(ripley)

v execute() metóde akcie, by sme akciu Use použili takto:

1 new Use<>(energy).scheduleOn(ripley);

Použitie kladiva na opravu reaktora (volanie hammer.useWith(reactor)v execute() metóde akcie) by zas vyzeralo takto:

1 new Use<>(hammer).scheduleOn(reactor);

Energy a iní Usable aktéri typovým argumentom odovzdanýmUsable obmedzujú, s akým typom aktéra dokážu pracovat’. Maloby preto byt’ možné použit’ pri akcii Use len takú kombináciu argu-mentu konštruktora a aktéra v metóde scheduleOn(), ktorá by totoobmedzenie zachovala (teda že v konecnom dôsledku by sme volaliuseWith() metódu so správnym typom argumentu). To dosiah-neme použitím typového parametra aj v akcii Use, ktorým tento typspolupracujúceho aktéra vymedzíme. Trieda AbstractAction má tiež

typový parameter, nezabudnite hopreto vhodne konkretizovat’: musí tobyt’ aktér takého typu, ktorý chceme,aby bol akceptovatel’ný v metódescheduleOn() a ako návratováhodnota getActor().

Nezabudnite v metóde execute() vyvolat’ použitie použitel’néhopredmetu za pomoci aktéra vykonávajúceho akciu a potom zavolat’metódu setDone(true) na signalizáciu ukoncenia akcie.

Úloha 1.6

V rámci scenára naplánujte akciu, ktorá zabezpecí automatické použi-tie lekárnicky v prípade, že sa dostane do kontaktu s Ripleyovou.

Skomponujte novú akciu Use s vhodnou existujúcou akciou.Aby ste vedeli overit’, ci k zmene stavu energie Ripleyovej naozaj

došlo, pridajte zobrazenie stavu jej energie do okna hry. Viete torealizovat’ volaním metódy drawText()1 nad grafickou vrstvou

1 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/graphics/Overlay.html#drawText(java.lang.String,int,int)

Overlay2 nad zobrazenou hrou, ku ktorej sa dostanete zo scény

2 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/graphics/Overlay.html

takto:

1 scene.getGame().getOverlay();

Aby bol text energie horizontálne zarovnaný s textom FPS, použitev metóde drawText() y-ovú pozíciu (yTextPos) vypocítanú nasle-dovne:

Hodnotu x-ovej súradnice nastavte podl’a potreby.Text zobrazený pomocou metódy drawText() je zobrazený len

na 1 snímok. Ked’že energia by sa mala zobrazovat’ neustále, potrebu-jeme zabezpecit’ opakované volanie vykreslenia (vypísania) jej stavu.

Page 74: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

66 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

1 int windowHeight = scene.getGame().getWindowSetup().getHeight();

2 int topOffset = GameApplication.STATUS_LINE_OFFSET;

3 int yTextPos = windowHeight - topOffset;

Docielite to bud’ naplánovaním s vhodnými akciami, alebo umiest-nením vykresl’ovania v rámci triedy scenára do (prekrytej) metódysceneUpdating(), ktorá je scénou volaná vždy pred vykreslenímnového snímku.

Úloha 1.7

Overte správnost’ svojej implementácie.Docasne upravte pociatocnú hodnotu energie Ripleyovej, aby ste

overili správanie lekárnicky. Tá by mala zmiznút’ zo scény len akRipleyová pri prechode cez nu nebude mat’ plnú energiu.

Obr. VII.3: Ripleyová a lekárnicka.

Úloha 1.8

Podobným spôsobom ako v prípade Energy vytvorte v balíkusk.tuke.kpi.oop.game.items triedu Ammo a overte správnost’svojej implementácie.

Trieda Ammo bude reprezentovat’ zásobník, ktorý vždy povzbudíRipleyovej náladu tým, že zvýši pocet nábojov v jej zbrani.

Zabezpecte nasledovné správanie:

• Vziat’ zásobník bude vediet’ len inštancia triedy Ripley.

• Množstvo nábojov bude zväcšené o 50.

• Maximálne množstvo nábojov, ktoré Ripleyová unesie naraz vovreckách, je 500.

Page 75: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

USABLE ITEMS 67

• Po tom, ako Ripleyová "použije" zásobník, tento odstránte zo scény.

• Pokial’ bude mat’ Ripleyová plný stav nábojov, ku žiadnemu dobitiuani odstráneniu zo scény nedôjde.

Ako sprite pre reprezentáciu zásobníka použite súbor s názvomammo.png (Obr. VII.4). Obr. VII.4: Sprite ammo.png (rozmery

spritu: 16x16).Nezabudnite, že pre správne fungovanie triedy je potrebnézabezpecit’ aj úpravu triedy Ripley. Vytvorte v nej preto clenskúpremennú na uchovávanie množstva nábojov a zodpovedajúci gettera setter pre prístup k nej.

Krok 2: !Samsonite Backpack iterator

Vašou úlohou teraz bude podl’a návodu, ktorý vypracoval náš tak-tický a strategický tím, vytvorit’ batoh, ktorým bude Ripleyová vy-bavená. Tento batoh jej umožní mat’ poruke rôzne predmety, ktorémôže potrebovat’ v priebehu misie. Vypracovaný návod zárovenukazuje spôsob, ako Ripleyovú naucit’ rozpoznat’ predmety, ktoré sado batoha zmestia.

Aby ste mali na com stavat’, náš technologický tím zárovenpripravil univerzálne rozhranie ActorContainer, ktoré predstavujeLIFO kolekciu urcitého typu aktérov. Toto rozhranie by mal vamivytvorený batoh implementovat’.

<<interface>>Actor

<<interface>>ActorContainer

<<interface>>Keeper

Backpack

Ripley

<<interface>>Collectible

Obr. VII.5: Trieda Backpack implemen-tujúca rozhranie ActorContainera rozhranie Keeper reprezentujúceaktérov s kontajnerom.Úloha 2.1

V balíku sk.tuke.kpi.oop.game.items vytvorte podl’a uve-deného diagramu rozhranie Collectible, ktoré bude oznacovat’predmety, ktoré bude možné ukladat’ do batoha.

Toto rozhranie bude rozširovat’ rozhranie Actor a nebude defi-novat’ žiadne d’alšie metódy. Bude teda slúžit’ ako marker interface3, 3 https://en.wikipedia.org/

wiki/Marker_interface_patternktorý v rámci typového systému definuje nový typ na odlíšenieskupiny objektov od ostatných - v tomto prípade na odlíšenie aktérov,ktorých bude možné vkladat’ do batoha.

Page 76: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

68 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 2.2

V balíku sk.tuke.kpi.oop.game.items vytvorte triedu Back-

pack, ktorá bude implementovat’ rozhranie ActorContainer. Rozhranie ActorContainer sanachádza v hernej knižnici.Pri implementácii Backpack-u potrebujete konkretizovat’ typový

parameter rozhrania ActorContainer. Ked’že chceme, aby Ripleyovámohla prenášat’ v batohu len predmety na to urcené, použite tu typCollectible.

Batoh sa bude správat’ ako zásobník (LIFO4. Pre ukladanie prvkov 4 https://en.wikipedia.org/wiki/LIFO_%28computing%29môžete využit’ jednu z kolekcií, ktoré ponúka jazyk Java, napr Ar-

rayList.Konštruktor batoha bude mat’ nasledovnú signatúru:

1 public Backck(String name, int capacity)

• name reprezentuje meno batoha,

• capacity definuje maximálnu kapacitu (teda poctu predmetov,ktoré bude možné naraz v batohu niest’)

Úloha 2.3

V triede Backpack implementujte metódy getCapacity(), get-Content(), getName() a getSize() z rozhrania ActorCon-tainer.

• getCapacity() bude predstavovat’ getter pre kapacitu batoha.

• getContent() vráti kópiu zoznamu predmetov v batohu. Jedôležité, aby modifikácie tohto zoznamu neovplyvnili samotnýobsah batoha!

Pre vytvorenie kópie zoznamu môžetepoužit’ vhodnú factory metódu dostupnúna rozhraní List (https://docs.oracle.com/javase/10/docs/api/java/util/List.html).• getName() vráti názov kontajnera (batoha), ktorý sa v hre vykreslí

popri jeho obsahu.

• getSize() vráti aktuálny pocet predmetov v batohu.

Úloha 2.4

Vytvorte metódu add() rozhrania ActorContainer, pomocouktorej budete vediet’ vložit’ do batoha nový predmet.

Pri implementácii metódy dodržte nasledovné správanie:

• Predmety budú v kolekcii uložené v rovnakom poradí, v akom bolipridávané do batoha.

• Do batoha bude možné vložit’ maximálne tol’ko predmetov, kol’kobolo zadaných pri jeho vytváraní argumentom capacity.

Page 77: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

USABLE ITEMS 69

• Ak bude batoh plný a aj napriek tomu bude metóda pre vloženiepredmetu do batoha zavolaná, vyvolajte vlastnú runtime výnimkuIllegalStateException5, ktorej v konštruktore odovzdáte 5 https://docs.oracle.com/

javase/10/docs/api/java/lang/IllegalStateException.html

správu "<backpack name> is full" kde <backpack name>

nahradíte menom batoha.

Výnimka sa v jazyku Java vyvoláva pomocou príkazu throw:

1 throw new IllegalStateException();

Úloha 2.5

Vytvorte metódu remove() rozhrania ActorContainer, pomocouktorej odstránite predmet z batoha.

Úloha 2.6

Vytvorte metódu iterator() rozhrania ActorContainer, pomo-cou ktorej bude možné vrátit’ referenciu na iterátor batoha.

Rozhranie ActorContainer rozširuje rozhranie Iterable<E>,ktoré definuje metódu iterator(). Implementáciou tejto metódyzískame možnost’ iterovat’ obsahom batoha prostredníctvom tzv.rozšíreného for cyklu, ako ilustruje nasledovná ukážka:

1 for (Collectible item : backpack) {

2 // pouzitie predmetu (item) z batohu

3 }

Pri implementácii metódy postací vrátit’ iterátor dostupný z kolek-cie, ktorá uchováva obsah batoha.

Týmto realizujeme návrhový vzor Iterator. Návrhový vzor Iterator je popísaný napr.na stránke SourceMaking:https://sourcemaking.com/design_patterns/iteratorÚloha 2.7

V triede Backpack vytvorte metódu peek(), ktorá vráti referenciuna predmet, ktorý sa nachádza navrchu.

Batoh je reprezentovaný ako zásobník. Je dôležité, aby ste kedykol’vekvedeli získat’ referenciu na posledný vložený predmet, pretože totobude predmet, s ktorým budete vediet’ vykonávat’ rozlicné operácie(napr. použit’ ho alebo položit’ na zem).

Úloha 2.8

Vytvorte metódu shift() rozhrania ActorContainer, ktoráposledne pridaný predmet presunie na dno batoha.

Page 78: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

70 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

V kontajneri môžete vždy pracovat’ len s aktérom, ktorý je navrchu.Preto, ak budete potrebovat’ pracovat’ s niektorým aktérom vloženýmhlbšie v kontajneri, potrebujete jeho obsah preusporiadat’. Miestotoho, aby ste aktérov z kontajnera povyberali a povkladali ich spät’v poradí, v ktorom potrebujete, ich môžete preusporiadat’ priamo vkontajneri pomocou jeho metódy shift().

Príklad použitia by teda mohol vyzerat’ nasledovne: ak sa v konta-jneri nachádzajú aktéri v poradí D, C, B, A (od posledne vloženého poprvý vložený), tak po zavolaní metódy shift() bude poradie aktérovv kontajneri C, B, A, D.

Pre zmenu poradia predmetov v batohumôžete využit’ vhodnú statickú metóduz utilitnej triedy Collections.

Úloha 2.9

V balíku sk.tuke.kpi.oop.game vytvorte rozhranie Keeper, ktorébude rozširovat’ rozhranie Actor a bude reprezentovat’ aktérovvlastniacich nejaký ActorContainer.

Rozhranie bude mat’ typový parameter viazaný na typ Actor,ktorým sa vymedzí typ aktérov v kontajneri.

Rozhranie pridá k aktérovi jednu nasledovnú metódu:

1 ActorContainer<A> getContainer();

kde A reprezentuje spomínaný typový parameter.

Úloha 2.10

Upravte triedu Ripley tak, aby implementovala rozhranie Keeper avybavte ju vytvoreným batohom Backpack.

Batohu nastavte kapacitu na 10 predmetov a môžete ho nazvat’napríklad "Ripley’s backpack".

Úloha 2.11

Upravte triedy Hammer, Wrench, FireExtinguisher tak, abyimplementovali rozhranie Collectible.

Po tejto úprave sa objekty spomenutých tried budú dat’ vkladat’ dobatoha.

Úloha 2.12

Zobrazte batoh Ripleyovej, naplnte ho aspon troma rôznymi pred-metmi a otestujte svoju implementáciu.

Obsah ActorContainer-ov je možné v hre aj graficky znázornit’(vid’ obrázok nižšie). V rámci scenára na to použite metódu pushAc-

torContainer()6 nad objektom typu Game (ktorý získate zo scény).

6 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/Game.html#pushActorContainer(sk.tuke.kpi.gamelib.ActorContainer)

Page 79: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

USABLE ITEMS 71

V rámci scenára naplnte batoh troma predmetmi a skontrolujte,ci posledne pridaný predmet sa bude nachádzat’ v zobrazenombatohu celkom vl’avo. Skúste zavolat’ shift() metódu pre overeniepreusporiadania predmetov.

Obr. VII.6: Ripleyová vybavená batohom.

Krok 3: man backpack

V tomto kroku naucíme Ripleyovú používat’ vami vytvorený batoh.Vytvoríte preto niekol’ko akcií, vd’aka ktorým by to mohla Ripleyovábez problémov zvládnut’. Zaspomínate si na princíp polymorfizmu, vsúlade s ktorým sa javí výhodné neobmedzit’ tieto akcie len na prácuRipleyovej s batohom, ale implementovat’ ich pre akéhokol’vek Keeper-avlastniaceho akýkol’vek typ kontajnera ActorContainer.

Akcie by mali byt’ prispôsobené na akýkol’vek typ aktérov v konta-jneri. Preto ich vytvoríme s typovým parametrom, ktorým budememôct’ typ aktérov konkretizovat’ v triedach vytváraných akcií.

Shift

<<interface>>ActorContainer Take

Drop

<<abstract>>AbstractAction

Obr. VII.7: Triedy akcií na prácu skontajnermi aktérov.

Page 80: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

72 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 3.1

Vytvorte akciu Take, pomocou ktorej bude možné vložit’ do kontajn-era kompatibilný predmet nachádzajúci sa na scéne v kolízii s Keeperaktérom vykonávajúcim akciu.

Všetky akcie vytvárajte v rámcibalíka s akciami ako podtriedyAbstractAction.

Kompatibilným predmetom sa myslí predmet takého typu, ktorýje možné uložit’ do kontajnera vlastneného Keeper aktérom. Triedaakcie Take tak bude opät’ využívat’ typový parameter, ktorý budereprezentovat’ typ kompatibilných aktérov. Na základe tohto parame-tra bude potrebné aj vhodne dodefinovat’ typ Keeper aktéra, ktorýmôže akciu vykonávat’ (ktorý bude odovzdaný ako typový parameterpre AbstractAction).

Deklarácia konštruktora akcie bude vyzerat’ nasledovne:

1 public Take(Class<T> takableActorsClass)

kde:

• T zodpovedá typovému parametru popísanému vyššie,

• takableActorsClass typu Class<T> je referencia na runtimereprezentáciu triedy 7 aktérov, ktorých je možné vložit’ do batoha. 7 https://docs.oracle.com/

javase/10/docs/api/java/lang/Class.html

V metóde execute() nájdite v scéne prvého aktéra, ktorý je vkolízii s Keeper aktérom vykonávajúcim akciu, a ktorý je zárovenkompatibilného typu. Ak takého nájdete, pridajte ho do kontajneraKeeper aktéra a odstránte ho zo scény.

Pri implementácii metódy budete potrebovat’ kontrolovat’ typaktérov nachádzajúcich sa na scéne. V dôsledku obmedzenia JVMplatformy8 sa však typové parametre nedajú použit’ s instanceof. 8 https://docs.oracle.com/

javase/tutorial/java/generics/genTypes.html

Runtime reprezentácia triedy aktéra kompatibilného s kontajnerom(parameter konštruktora) však má nasledovné metódy, ktoré vietevyužit’:

• isInstance() namiesto instanceof

• cast() namiesto bežného pretypovania.

Vyhl’adanie kompatibilného aktéra, ktorý je v kolízií s Keeperaktérom, je možné prehl’adne vyriešit’ použitím stream API9. 9 https://docs.oracle.com/

javase/10/docs/api/java/util/stream/Stream.html

Nezabudnite zabezpecit’, aby vždy v rámci vykonávania metódyexecute() došlo k nastaveniu isDone stavu akcie na true, ked’žeakcia Take je jednorázová.

Page 81: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

USABLE ITEMS 73

Úloha 3.2

Ošetrite možný vznik výnimky IllegalStateException v exe-

cute() metóde akcie Take.Ked’že akcia Take pridáva aktérov do kontajnera, môže pri volaní

mtódy add() dôjst’ k vzniku výnimky IllegalStateException.Namiesto toho, aby v takom prípade aplikácia padla, však budemechciet’ zobrazit’ správu z výnimky hrácovi na obrazovke. Preto jepotrebné výnimku spracovat’ a vhodne odprezentovat’.

V Jave je možné výnimky zachytávat’ v rámci bloku try a spraco-vat’ konkrétne typy výnimiek v nasledovnom bloku catch:

1 try {

2 // kod ktory moze sposobit vynimku

3 } catch (Exception ex) {

4 // spracovanie vynimky typu Exception

5 }

V prípade vzniku výnimky pri plnomkontajneri neodstranujte nájdenéhoaktéra v kolízii zo scény.

Správu z výnimky získate metódou getMessage() a môžete juzobrazit’ podobným spôsobom ako stav energie - do vrstvy Overlay.Aby sa však správa zobrazila napríklad na 2 sekundy, môžete využit’metódu showFor() objektu OverlayDrawing10, korý získate z

10 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/graphics/OverlayDrawing.html#showFor(float)

volania metódy drawText():

1 overlay.drawText(exception.getMessage(), x, y).showFor(2);

Úloha 3.3

Vytvorte akciu Drop, pomocou ktorej bude možné vyložit’ aktéra zvrchu kontajnera do scény na miesto, kde sa nachádza Keeper aktérvykonávajúci akciu.

Signatúra triedy bude obdobná ako pri akcii Take. Ked’že ale pritejto akcii nebudeme potrebovat’ vykonávat’ instanceof kontrolynad typovým parametrom, konštruktor akcie bude bezparametrický. Pri používaní tejto akcie (pri vytváraní

inštancií) bude potrebné špecifikovat’typový argument pre typ aktérov vkontajneri explicitne, ked’že typovýsystém ho nebude mat’ na základe cohoodvodit’. Konštruktor akcie je totižbezparametrický.

Pri implementácii metódy execute() vyberte z kontajnera ak-téra, ktorý je na vrchu a umiestnite ho do scény tak, aby sa jeho stre-dová pozícia zhodovala so stredovou pozíciou Keeper aktéra, ktorývykonáva akciu. Nezabudnite zabezpecit’ ukoncenie akcie.

Page 82: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

74 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 3.4

Vytvorte akciu Shift, pomocou ktorej zabezpecíte zmenu poradiapredmetov v kontajneri.

Ked’že v akcii Shift len meníme poradie prvkov kontajnerapomocou existujúcej bezparametrickej metódy, akcia nepotrebujepriamo pracovat’ s aktérmi v kontajneri a nepotrebuje tak poznat’ aniich konkrétny typ. Trieda akcie teda nepotrebuje typový parametera typ aktérov kontajnera v typovom argumente AbstractActionmôžeme nahradit’ zástupným znakom11 "?". 11 https://docs.oracle.com/

javase/tutorial/extra/generics/wildcards.html

Konštruktor akcie bude opät’ bezparametrický a pre metódu exe-

cute() opät’ platí potreba zmeny stavu akcie na ukoncenú.

Úloha 3.5

V novom balíku sk.tuke.kpi.oop.game.controllers vytvortetriedu CollectorController implementujúcu rozhranie Key-boardListener. Tento ovládac bude slúžit’ na plánovanie akciíTake, Drop a Shift na Keeper<Collectible> aktérovi pomocouklávesnice.

Referenciu na ovládaného aktéra získajte pomocou parametrickéhokonštruktora. Dalej prekryte metódu keyPressed() a implementu-jte plánovanie akcií na prácu s kontajnerom nasledovne:

• Enter - vezme predmet do batoha

• Backspace - vyloží posledne vložený predmet z batoha

• S - posunie predmety v batohu, cím dôjde k zmene predmetu navrchu batoha

Úloha 3.6

Overte správnost’ svojej implementácie.Aby vám fungoval nový CollectorController na prácu s

Ripleyovej batohom pomocou kláves, nezabudnite v rámci scenáravytvorit’ inštanciu tejto triedy controller-a a nastavit’ ho ako d’alšílistener pre spracovanie vstupu.

Dôkladne vyskúšajte správnost’ fungovania akcií pri stlácaníkláves, ktoré im zodpovedajú. Okrem základného fungovania klávesa akcií na prácu s batohom skontrolujte aj neobvyklé situácie, akonapríklad

• stlacenie klávesy na pridanie predmetu do batoha, ked’ jeho ka-pacita je už naplnená,

• stlacenie klávesy na vyloženie predmetu z batoha, ked’ je ten všakprázdny,

Page 83: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

USABLE ITEMS 75

• stlacenie klávesy na zmenu poradia predmetov v batohu, ked’ jeprázdny a potom ked’ je jeho kapacita naplnená.

Doplnujúce úlohy

Úloha A7.1

KeyboardController vytvorený na minulom cvicení premenujtena MovableController a presunte do balíka sk.tuke.kpi.oop.game.controllers.

Dôvod premenovania je, že daný ovládac bude slúžit’ len na ovlá-danie pohybu a MovableController bude teda výstižnejší názov.

Doplnujúce zdroje• Návrhový vzor Iterator

https://sourcemaking.com/design_patterns/iterator

• Návrhový vzor Marker Interfacehttps://en.wikipedia.org/wiki/Marker_interface_pattern

• Utilitná trieda Collectionshttps://docs.oracle.com/javase/10/docs/api/java/util/Collections.html

• Rozšírený for cyklushttps://explainjava.com/for-each-loop-java/

• Výnimka IllegalStateExceptionhttps://docs.oracle.com/javase/10/docs/api/java/util/Collections.html

• Rozhranie Overlay v knižnici GameLibhttp://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/

graphics/Overlay.html

• Java stream APIhttps://docs.oracle.com/javase/10/docs/api/java/util/stream/Stream.html

Page 84: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav
Page 85: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

VIIIMission Impossible

MOTIVÁCIA

Máme problém! Na 347. poschodí došlo k úniku vysoko toxického materiálu do ovzdušia! Bezpecnostnýsystém automaticky uzamkol kontaminované miestnosti a pracovníci, ktorí neboli kontaminovaní, bolievakuovaní do bezpecia. Zlyhal však odsávací systém, ktorý mal zabezpecit’ automatické odsatie kon-taminovaného vzduchu. Ked’že však máte bohaté skúsenosti s opravovaním predmetov kladivom, boli stevybratí, aby ste so svojou Ripleyovou pokazený ventilátor opät’ uviedli do chodu.

Taktický tím pre vás pripravil plán misie, ktorého striktné dodržanie musí bezpodmienecne viest’ k jejúspešnému splneniu. Z operacného strediska zdraví Manager.

C IELE

1. Naucit’ sa využívat’ návrhový vzor Abstract Factory.

2. Porozumiet’ herným mapám vytváraným v editore Tiled.

3. Využit’ návrhový vzor Observer (publish/subscribe).

4. Využit’ statické cleny triedy.

Krok 1: Welcome to the Real World!

Primárnym ciel’om tejto misie je naucit’ Ripleyovú pohybovat’ sa vnovom prostredí. Na dosiahnutie tohto ciel’a potrebujete pri vytváraníhernej scény nacítat’ mapu reprezentujúcu prostredie Ripleyovej, spolus okolitými, viac ci menej živými, aktérmi.

Aby to bolo možné, potrebujete najskôr vytvorit’ factory triedu,pomocou ktorej bude vediet’ vaša simulácia nakonfigurovat’ patricnúsituáciu a rozmiestnit’ aktérov do ich pociatocných pozícií podl’aúdajov zaznacených v mape. A ked’že mapa môže obsahovat’ aj steny,bude potrebné naucit’ Ripleyovú ich rozoznávat’ a neprechádzat’ skrzene.

Page 86: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

78 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 1.1

Stiahnite si archív s mapou pre dnešnú misiu, ktorý je na adresehttp://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/

download/levels/mission-impossible.zip a rozbal’te ho doadresára src/main/resources/maps/ v projekte.

Výsledná štruktúra súborov v adresári src/main/resources/mapsby mala byt’ nasledovná:

src/main/resources/maps/

` tilesets/

| ` tileset01.png

` mission-impossible.tmx

Úloha 1.2

V main() metóde projektu upravte volanie konštruktora triedyWorld tak, že k názvu scény pridáte druhý argument v podobe cestyk .tmx súboru s mapou, ktorá sa má do scény nacítat’.

Cestu k mape zapíšete ako maps/mission-impossible.tmx.

Úloha 1.3

V balíku pre scenáre vytvorte novú triedu pre scenár pomenovanúpodl’a tejto misie: MissionImpossible.

Trieda musí, samozrejme, implementovat’ rozhranie SceneLis-tener a scenár budete neskôr písat’ do metódy sceneInitial-

ized().

Úloha 1.4

V triede scenára MissionImpossible vytvorte vnorenú verejnústatickú triedu s názvom Factory, ktorá implementuje rozhranieActorFactory.

Táto trieda bude reprezentovat’ návrhový vzor továrenská metóda(Factory Method) a trieda samotná bude obsahovat’ len jednu metóducreate(String type, String name).

Úloha 1.5

Implementujte metódu create() v triede MissionImpossi-ble.Factory tak, aby vytvárala inštancie aktérov potrebných prednešnú misiu.

Herná mapa dnešnej misie obsahuje objekty s menami accesscard, door, ellen, energy, locker, ventilator. Zatial’ viete

Page 87: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

MISSION IMPOSSIBLE 79

poskytnút’ inštancie pre Ripleyovú (ellen) a lekárnicku (energy). Preiné mená z metódy create() vrát’te hodnotu null.

Metóda create() je volaná hernou knižnicou pri spracovávanímapy. Mapy sa vytvárajú pomocou editora Tiled. Sú to v podstate Strucný návod na prácu s editorom

Tiled je na adrese https://kurzy.kpi.fei.tuke.sk/oop/pages/tiled-tutorial.html

XML súbory, ktoré vo viacerých vrstvách definujú vzhl’ad hernéhosveta. Každý aktér, ktorého mapa definuje, má typ a meno (odtial’parametre metódy create() v rozhraní ActorFactory), ako ajsvoju pociatocnú polohu. Úlohou vytváranej továrne na aktérov je tedavytvorit’ inštancie, ktoré sa majú použit’ na reprezentáciu danéhoaktéra. Umiestnenie aktérov na danú pozíciu definovanú v mape užautomaticky zabezpecí scéna volaním metódy setPosition() nadzískaným aktérom.

Úloha 1.6

Nastavte inštanciu triedy MissionImpossible.Factory akotováren na aktérov pre scénu.

Vytvorenú inštanciu triedy MissionImpossible.Factory

prepojte s inštanciou scény tak, že ju v metóde main() odovzdajteako tretí argument konštruktora triedy World.

Úloha 1.7

V scenári zabezpecte nastavenie ovládania Ripleyovej pomocou ovlá-dacov MovableController a CollectorController, zobrazeniejej batohu a stavu energie.

Ked’že je teraz Ripleyová vytváraná cez továren na základe jej umiest-nenia v mape scény, inštanciu Ripleyovej už v scenári nevytvárajte, alezískajte už existujúcu inštanciu zo scény.

Pre redukciu duplikovania kódu potrebného na zobrazenie stavu(energie) Ripleyovej vytvorte v triede Ripley metódu showRip-

leyState() v ktorej vykreslenie potrebného textu zabezpecíte. Tútometódu potom zavolajte v metóde sceneUpdating() v scenári,alebo naplánujte na opakované volanie pomocou akcií.

Ak chcete, aby scéna sledovala pohyb Ripleyovej, využite na tometódu scene.follow()1. 1 http://oop-kniha.pages.kpi.

fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/Scene.html#follow(sk.tuke.kpi.gamelib.Actor)

Nezabudnite pridat’ novú triedu pre dnešný scenár ako listener nascénu v metóde main().

Úloha 1.8

Overte správnost’ implementácie.Ak ste postupovali správne, po spustení uvidíte scénu s mapou, na

ktorej sa už bude nachádzat’ lekárnicka a Ripleyová. Ripleyovú by ste

Page 88: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

80 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

mali vediet’ ovládat’ pomocou klávesnice, a zatial’ by mala zvládnut’prechádzat’ aj cez steny (Obr. VIII.1).

Obr. VIII.1: Ripleyová nachádzajúca sav reálnom svete zatial’ prechádza aj cezsteny.

Úloha 1.9

Zabezpecte, aby Ripleyová neprechádzala cez steny.Zistit’, ci je objekt typu Actor v kolízii so stenou, môžete pomocou

volania metódy intersectsWithWall() nad objektom mapy. Objekt mapy získate zo scény pomocoumetódy getMap().Nášmu taktickému tímu sa ako najvhodnejšie javí implementovat’

túto funkcionalitu do triedy akcie, ktorá sa stará o pohyb aktérov.V mape sú steny definované v rámci vrstvy s názvom walls. Táto

vrstva nie je v rámci scény graficky vykreslená, avšak informácie ztejto vrstvy (vyplnené, respektíve prázdne dlaždice) sú použité navytvorenie stien v miestach vyplnených dlaždíc.

Obr. VIII.2: Mapa scény so zobrazenouvrstvou walls v editore Tiled.

Ak je vaša implementácia správna, od tohto momentu už Ripleyovánebude cez steny prechádzat’.

Page 89: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

MISSION IMPOSSIBLE 81

Krok 2: Alohomora!

Pri implementácii triedy MissionImpossible.Factory ste siurcite všimli, že ste nemali k dispozícii všetkých potrebných aktérovdefinovaných v mape. V rámci plnenia tohto kroku misie niekol’kochýbajúcich predmetov vytvoríte. Konkrétne budete vytvárat’ dverea prístupovú kartu, pomocou ktorej bude možné zamknuté dvereodomknút’.

Pri plnení tohto kroku misie bude potrebné aj rozšírit’ možnostipoužitel’ných predmetov, aby ste ich mohli používat’ interaktívne -pomocou klávesnice.

AccessCard

LockedDoor

<<interface>>Usable

<<interface>>Collectible

<<abstract>>AbstractActorDoor

<<interface>>Actor

<<interface>>Openable

Obr. VIII.3: Dvere, zamknuté dvere aprístupová karta na odomykanie.

Úloha 2.1

V novom balíku sk.tuke.kpi.oop.game.openables vytvorterozhranie Openable, ktoré bude reprezentovat’ otváratel’né objekty.

Rozhranie bude rozširovat’ rozhranie Actor a bude mat’ nasle-dovné metódy:

• void open() - otvorenie predmetu (aktéra)

• void close() - zatvorenie predmetu (aktéra)

• boolean isOpen() - vráti true, ak je predmet (aktér) otvorený, vopacnom prípade vráti false

Úloha 2.2

V balíku pre otváratel’ných aktérov vytvorte podl’a vyššie uvedenéhodiagramu triedu Door reprezentujúcu bežné dvere v hre a implemen-tujte v nej metódy z rozhraní Openable a Usable.

Trieda Door bude implementovat’ rozhranie Openable a takistoUsable. Dvere budú použitel’né s akýmkol’vek aktérom, preto akotypový argument typu Usable použite typ Actor.

Page 90: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

82 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Pre aktuálnu misiu budeme potrebovat’ vertikálne otocené dvere,preto ako animáciu použite obrázok vdoor.png (Obr. VIII.4). Obr. VIII.4: Animácia vertikálnych dverí

vdoor.png (rozmery spritu: 16x32,trvanie snímku: 0.1)Vo východzom stave budú dvere zavreté. Pri použití dverí niek-

torým z aktérov dvere otvorte, ak sú zavreté a zatvorte ich, ak už súotvorené. Pri animovaní otvárania a zatvárania

dverí viete využit’ režimy prehrávaniaanimácie ONCE a ONCE_REVERSED,ktoré viete nastavovat’ metódousetPlayMode() na existujúcej ani-mácii, spolu s jej metódami play() astop().

Úloha 2.3

Doplnte implementáciu dverí tak, aby cez ne nebolo možné prejst’,ked’ sú zavreté.

Nášmu taktickému a strategickému tímu sa ako najlepší spôsobznepriechodnenia zatvorených dverí javí vytvorit’ na ich mieste vmape stenu. Pri ich otvorení je zase potrebné stenu zrušit’.

Všetky steny sú v rámci hernej mapy definované vo vrstve walls,ktorú ste videli už na obrázku vyššie. Pri práci s editorom Tiled sú Editor dlaždicových máp

Tiled je dostupný na adresehttps://mapeditor.org.

mapy vytvárané pomocou dlaždíc, ktoré sú v našom prípade vel’ké16x16 pixelov. Každá vyplnená dlaždica vo vrstve walls reprezentujestenu.

Aj v rámci objektovej reprezentácie mapy máme k dispozíciidlaždice. Každá dlaždica pokrývajúca mapu má svoju x-ovú a y-ovú súradnicu, ktorá reprezentuje poradie dlaždice v smere osi x ay, pricom pociatok súradnicového systému je v l’avom dolnom rohumapy. Dlaždica na tomto umiestnení má súradnice [0, 0].

Obr. VIII.5: Dlaždice mapy s vyznace-nou dlaždicou so súradnicami mriežky[3, 5]

Konkrétnu dlaždicu viete získat’ pomocou metódy getTile()2

2 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/map/SceneMap.html#getTile(int,int)

nad objektom mapy. Táto dlaždica je typu MapTile3 a okrem jej pozí-3 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/map/MapTile.html

cie a rozmerov z nej viete metódou isWall() zistit’, ci daná pozíciav mape je považovaná za stenu. Konecne, metódou setType()

viete typ dlaždice zmenit’ na jednu z dvoch hodnôt enumerácie Map-Tile.Type4: 4 http://oop-kniha.pages.kpi.

fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/map/MapTile.Type.html

• CLEAR - miesto, kde sa dlaždica tohto typu nachádza, je priechodzie,

• WALL - miesto, kde sa dlaždica tohto typu nachádza, je považovanéza stenu.

Uvedomte si, že jednotky súradníc dlaždíc sa nezhodujú s jed-notkami súradníc napr. aktérov. Preto budete potrebovat’ robit’ pre-pocet z pozícií definovaných v pixeloch do pozícií definovaných

Page 91: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

MISSION IMPOSSIBLE 83

v indexe dlaždice v mriežke. Pri výpocte vychádzajte z vel’kostidlaždice. Nezabudnite na to, že dvere svojou

plochou pokrývajú dve dlaždice. Obomje potrebné menit’ stav pri otváraní azatváraní dverí.Úloha 2.4

Upravte create() metódu v MissionImpossible.Factory tak,aby pre meno aktéra "door" vrátila inštanciu triedy Door a overtesvoju implementáciu.

V scéne by mali pribudnút’ dvere a Ripleyová by sa nemala cez nevediet’ dostat’ do menšej miestnosti (Obr. VIII.6).

Obr. VIII.6: Ripleyová stojí pred dverami,ktoré ešte nedokáže otvorit’.

Úloha 2.5

Do rozhrania Usable a do každého konkrétneho aktéra implementu-júceho toto rozhranie pridajte metódu getUsingActorClass().

V nasledujúcej úlohe budete pridávat’ podporu pre plánovanieakcie Use pomocou klávesnice. Scenár použitia je napríklad takýto:

1. Ripleyová príde k dverám, ktoré implementujú rozhranie Usable.

2. Stlacením priradenej klávesy hrác signalizuje zámer otvorit’ dvere.

3. Akcia Use je naplánovaná tak, aby sa dvere použili s Ripleyovou.

Iný scenár použitia, ktorý budete implementovat’ neskôr, budenasledovný:

1. Ripleyová s prístupovou kartou v batohu príde k uzamknutýmdverám.

2. Stlacením priradenej klávesy hrác signalizuje zámer použit’ pred-met na vrchu batoha.

Page 92: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

84 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

3. Akcia Use je naplánovaná tak, aby sa prístupová karta (predmet zbatoha) použila so zamknutými dverami (predmet v scéne v kolíziis Ripleyovou).

Ako je viditel’né predovšetkým vdruhom prezentovanom scenári použi-tia, Ripleyová tu úcinkuje ako sprostred-kovatel’ použitia predmetu, ktorý sanachádza v jej blízkosti.

Vzhl’adom na obmedzenie JVM platformy, ktoré sme spomínali užpri akcii Take, nie je možné pocas behu programu pracovat’ priamos typmi reprezentovanými typovými parametrami (tie existujú lenpocas kompilácie). Preto pridávanou metódou getUsingActor-

Class() budeme pre každý použitel’ný predmet explicitne vracat’runtime reprezentáciu triedy aktéra, s ktorým daný použitel’ný pred-met dokáže pracovat’. Táto reprezentácia triedy sa využije pri hl’adaníkompatibilného aktéra, s ktorým môže byt’ akcia Use naplánovaná.

Nová metóda v rozhraní Usable nech má nasledujúcu signatúru:

1 Class<T> getUsingActorClass();

2 // T reprezentuje typovy parameter v triede Usable

V každom použitel’nom aktérovi, ktorý dosadzuje konkrétnytyp kompatibilného aktéra do typového argumentu pre Usable,vrát’te z tejto metódy referenciu na runtime reprezentáciu triedykompatibilného aktéra. V prípade kladiva (triedy Hammer), ktoréje použitel’né s reaktorom, bude implementácia tejto metódy tedavyzerat’ nasledovne:

1 public Class<Reactor> getUsingActorClass() {

2 return Reactor.class;

3 }

Úloha 2.6

V akcii Use pridajte metódu scheduleOnIntersectingWith(Actor

mediatingActor), pomocou ktorej bude možné naplánovat’ Useakciu na aktérovi, ktorý je kompatibilný s Usable predmetom odovz-daným konštruktoru akcie a nachádza sa v kolízii so sprostredku-júcim aktérom reprezentovaným parametrom mediatingActor.

Táto metóda je potrebná v triede akcie Use kvôli tomu, lebo potre-bujeme v kontexte, v ktorom typový systém jazyka má k dispozíciitypový argument Usable predmetu, nájst’ prvého kompatibilnéhoaktéra na scéne v kolízií so sprostredkujúcim aktérom (predovšetkýmRipleyovou). To nám v d’alšej úlohe umožní interaktívne plánovat’akciu Use ako reakciu na stlacenie klávesy.

Ak máte funkcnú implementáciu akcie Use, kde clenská premennáusable reprezentuje použitel’ného aktéra odovzdaného konštruktoru

Page 93: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

MISSION IMPOSSIBLE 85

akcie a T reprezentuje typový parameter akcie, je možné túto metóduimplementovat’ s využitím stream API nasledovne:

1 public Disposable scheduleOnIntersectingWith(Actor mediatingActor) {

2 Scene scene = mediatingActor.getScene();

3 if (scene == null) return null;

4 Class<T> usingActorClass = usable.getUsingActorClass();

5 return scene.getActors().stream() // ziskame stream akterov na scene

6 .filter(mediatingActor::intersects) // vyfiltrujeme akterov, ktori su

7 // v kolizii so sprostredkovatelom

8 .filter(usingActorClass::isInstance) // vyfiltrujeme akterov

9 // kompatibilneho typu

10 .map(usingActorClass::cast) // vykoname pretypovanie streamu akterov

11 .findFirst() // vyberieme prveho (ak taky existuje) aktera zo streamu

12 .map(this::scheduleOn) // zavolame metodu scheduleOn s najdenym

13 // akterom a vratime Disposable objekt

14 .orElse(null); // v pripade, ze ziaden vyhovujuci akter nebol najdeny,

15 // vratime null

16 }

Ekvivalentná implementácia "klasickým" spôsobom by vyzeralanasledovne:

1 public Disposable scheduleOnIntersectingWith(Actor mediatingActor) {

2 Scene scene = mediatingActor.getScene();

3 if (scene == null) return null;

4 Class<T> usingActorClass = usable.getUsingActorClass();

5 for (Actor actor : scene) {

6 if (mediatingActor.intersects(actor)

7 && usingActorClass.isInstance(actor)) {

8 return this.scheduleOn(usingActorClass.cast(actor));

9 }

10 }

11 return null;

12 }

Page 94: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

86 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 2.7

Do ovládaca CollectorController pridajte plánovanie akcie Usepre predmety na scéne.

Pri stlacení klávesy U naplánujte použitie prvého nájdenéhopoužitel’ného predmetu v kolízii s ovládaným aktérom. Ovládaný ak-tér bude následne vystupovat’ v úlohe sprostredkovatel’a pre nájdeniekompatibilného predmetu pomocou pridanej metódy scheduleOn-

IntersectingWith().Pri riešení úlohy budete v ovládaci potrebovat’ vykonat’ prety-

povanie všeobecného aktéra na Usable aktéra, no nebudete mat’informáciu o tom, ktorý konkrétny podtyp aktéra je typovým argumen-tom nájdeného použitel’ného aktéra. Použite teda zástupný (wildcard)symbol ? namiesto konkrétneho typového argumentu. Pretypovaniemôže vyzerat’ takto:

1 (Usable<?>) actor

Úloha 2.8

Overte správnost’ svojej implementácie.Ak postupujete správne, Ripleyová by mala vediet’ otvorit’ dvere, ku

ktorým sa priblíži, stlacením klávesy U.

Úloha 2.9

Podl’a diagramu tried na zaciatku kroku vytvorte v balíku preotváratel’ných aktérov triedu LockedDoor, ktorá bude dedit’ odtriedy Door a bude reprezentovat’ uzamknuté dvere.

Odstránit’ bezpecnostný zámok však bude možné len použitímsprávnej prístupovej karty, co budete implementovat’ v d’alšejúlohe. Po odomknutí dverí ich už bude možné kedykol’vek otvorit’ azatvorit’, tak ako bežné dvere.

V triede implementujte metódy:

• void lock() - zamknutie (a zároven zatvorenie) dverí,

• void unlock() - odomknutie (a zároven otvorenie) dverí,

• boolean isLocked() - vráti aktuálny stav dverí - ci sú zamknutéalebo nie.

Úloha 2.10

Podl’a diagramu tried na zaciatku kroku vytvorte v balíku sk.tuke.kpi.oop.game.items

triedu reprezentujúcu prístupovú kartu AccessCard.

Page 95: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

MISSION IMPOSSIBLE 87

Táto karta bude implementovat’ rozhrania Collectible a Us-able a bude použitel’ná práve s uzamknutými dverami LockedDoor.Použitím karty sa uzamknuté dvere odomknú.

Animácia reprezentujúca prístupovú kartu je uložená v súborekey.png (Obr. VIII.7). Obr. VIII.7: Animácia key.png

(rozmery spritu: 16x16)

Úloha 2.11

Pridajte do ovládaca CollectorController naplánovanie akcieUse pre predmety na vrchu batoha.

Pri stlacení klávesy B naplánujte akciu Use na predmete na vrchubatoha v prípade, že je tento predmet použitel’ný. Opät’ využite ovlá-daného aktéra ako sprostredkovatel’a na nájdenie kompatibilnéhoaktéra v jeho blízkosti na scéne.

Úloha 2.12

Upravte create() metódu v MissionImpossible.Factory tak,aby pre meno "door" vytvárala inštanciu LockedDoor namiestoDoor, pre meno "access card" zas inštanciu AccessCard a overtesvoju implementáciu.

Overte, že použitím klávesy U už nie je možné otvorit’ zamknutédvere a že tieto sa otvoria, ak si Ripleyová vezme do batohu prístupovúkartu a použijete klávesu B po priblížení sa k dverám (Obr. VIII.8).

Obr. VIII.8: Ripleyová s prístupovou kar-tou v batohu prechádza odomknutýmidverami.

Krok 3: Missing Items

Pre úplnost’ aktérov definovaných v mape ešte chýba skrinka a ven-tilátor. Tie vytvoríte v tomto kroku. Takisto budeme potrebovat’

Page 96: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

88 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

rozšírit’ opravovacie schopnosti kladiva (schovávajúceho sa v skrinke)na akékol’vek opravitel’né predmety.

Locker

<<interface>>Usable

<<abstract>>AbstractActor

Ventilator

<<interface>>Repairable

Obr. VIII.9: Diagram tried znázornu-júci postavenie triedy Locker aVentilator

Úloha 3.1

Upravte kladivo tak, aby vedelo opravovat’ l’ubovol’ný Repairable

predmet a nie iba Reactor.Nezabudnite zmenit’ aj triedu získavanú metódou getUsin-

gActorClass(). Rovnako ako triedu Reactor.class môžetevrátit’ aj runtime reprezentáciu rozhrania Repairable ako Re-pairable.class.

Ked’že typovým argumentom rozhraniaUsable môže byt’ len podtyp Actor-a, zmena je potrebná aj v rozhraníRepairable, tak, aby toto rozhranierozširovalo rozhranie Actor.

Úloha 3.2

Podl’a uvedeného diagramu tried vytvorte v balíku sk.tuke.kpi.oop.game

triedu Locker, ktorá bude reprezentovat’ skrinku, po otvorení(použití) ktorej hrác nájde kladivo.

Nájdenie kladiva realizujte tým, že kladivo zo skrinky vypadne,akonáhle Ripleyová skrinku preskúma. Skrinka nech je použitel’nálen raz, takže Ripleyová preskúmaním jednej skrinky získa len jednokladivo.

Animácia reprezentujúca skrinku je uložená v súbore locker.png. Obr. VIII.10: Animácia locker.png(rozmery spritu: 16x16)

Úloha 3.3

Podl’a uvedeného diagramu vytvorte v balíku sk.tuke.kpi.oop.game

aj triedu Ventilator reprezentujúcu ventilátor, ktorý bude musiet’Ripleyová opravit’ kladivom.

Animácia reprezentujúca ventilátor je uložená v súbore ventila-tor.png. Obr. VIII.11: Animácia

ventilator.png (rozmery spritu:32x32, trvanie snímku: 0.1)

Page 97: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

MISSION IMPOSSIBLE 89

Ked’že ventilátor zacne v scéne vystupovat’ ako pokazený, zas-tavte spociatku prehrávanie jeho animácie. V metóde repair() zasreprezentujte opravenie ventilátora spustením prehrávania animácie.

Úloha 3.4

Dokoncite implementáciu MissionImpossible.Factory prevytváranie objektov na základe mien "ventilator" a "locker".

Krok 4: Entering Contaminated Zone

Vstupujeme do poslednej fázy dnešnej misie. Ciel’om je opravit’pokazený vetrák v zamorenej oblasti, cím nebezpecenstvo zamoreniapominie. Pri plnení tohto kroku si ukážeme ako pomocou správ viemereagovat’ na vzniknuté udalosti, pricom využijeme návrhový vzorObserver. Návrhový vzor Observer je popísaný

napríklad na stránke SourceMakinghttps://sourcemaking.com/design_patterns/observerÚloha 4.1

Pridajte do triedy Door témy správ o ich otvorení, respektíve zatvorení.Rôzne casti hry (iní aktéri, váš kód v rámci scenára, ...) môžu

chciet’ reagovat’ na to, ak sa nejaké dvere otvoria alebo zatvoria. Toumožníme vytvorením témy správ s definovaným typom obsahu(typom objektu, ktorý sa bude v danej téme posielat’) a publikovanímsprávy (konkrétneho objektu daného typu) do zbernice správ na scéne.V prípade dverí bude typom správy samozrejme typ Door.

Témy správ vytvoríte pomocou factory metódy Topic.create()5, 5 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/messages/Topic.html

ktorej prvý argument je názov témy a druhý typ objektu posielaný vsprávach.

Ked’že k témam budeme chciet’ pristupovat’ bez potreby mat’referenciu na konkrétne dvere, implementujte ich ako statické clensképremenné triedy Door. Téma pre otvorenie dverí môže vyzerat’ takto:

1 public static final Topic<Door> DOOR_OPENED = Topic.create("door opened",

2 Door.class);

Analogicky vytvoríte aj tému pre zatvorenie dverí.

Úloha 4.2

Publikujte správy o otvorení, respektíve zatvorení dverí.

Page 98: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

90 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

V metódach open() a close() dverí publikujte správu o tom,ktoré dvere boli práve otvorené, respektíve zatvorené. Využitemetódu publish()6 na objekte zbernice správ scény MessageBus7,

6 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/messages/MessageBus.html#publish(sk.tuke.kpi.gamelib.messages.Topic,M)7 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/messages/MessageBus.html

ktorý zo scény získate metódou getMessageBus().

Úloha 4.3

V scenári naplánujte akciu, v rámci ktorej bude dochádzat’ k pos-tupnému znižovaniu energie Ripleyovej v dôsledku rozširovaniakontaminácie po otvorení dverí.

Zbernica správ má metódu subscribe()8, ktorou sa vieme prih-

8 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/messages/MessageBus.html#subscribe(sk.tuke.kpi.gamelib.messages.Topic,java.util.function.Consumer)

lásit’ k "odberu" správ publikovaných v rámci urcitej témy. Prvýmargumentom je objekt témy správ a druhým lambda (resp. objekttypu funkcionálneho rozhrania Consumer9) s jedným parametrom -

9 https://docs.oracle.com/javase/10/docs/api/java/util/function/Consumer.html

objektom odoslaným v rámci konkrétnej správy.Prihláste sa k téme správ Door.DOOR_OPENED a zareagujte na

otvorenie dverí naplánovaním patricnej akcie na znižovanie energieRipleyovej. Odoberanie energie riešte vo vhodnom

intervale, aby neprebiehalo príliš rýchlo.

Úloha 4.4

Overte svoju implementáciu.Po otvorení dverí by mala zacat’ Ripleyovej klesat’ energia (Obr. ??).

Obr. VIII.12: Ripleyová v zamorenompriestore.

Úloha 4.5

Upravte triedu Ripley tak, aby sa po dosiahnutí energie 0 jej animá-cia zmenila na player_die.png (Obr. VIII.13) a publikujte správu ojej smrti.

Pre animáciu použite režim prehrávania Animation.PlayMode.ONCE.Vytváranú tému správ pomenujte RIPLEY_DIED.

Page 99: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

MISSION IMPOSSIBLE 91

Obr. VIII.13: Animácia umierajúcejRipleyovej player_die.png (rozmeryspritu: 32x32, trvanie snímku: 0.1)

Úloha 4.6

Zabezpecte, aby Ripleyová nebola po smrti ovládatel’ná ovládacmiMovableController a CollectorController.

Volanie metód registerListener() nad objektmi Input vraciareferenciu na Disposable objekt, ktorým môžete zrušit’ registrovanýlistener (obdoba Disposable objektov vrátených z metódy sched-

uleOn na rušenie akcií). Upravte teda implementáciu scenára tak, abyste po prijatí správy o smrti Ripleyovej zrušili listenery pre spomínanéovládace a znemožnili tak d’alšie ovládanie Ripleyovej.

Úloha 4.7

Zabezpecte, aby po oprave ventilátora došlo k odvetraniu kontamino-vaného priestoru a znižovanie energie Ripleyovej sa zastavilo.

Túto úlohu tiež riešte vytvorením témy správ pre opravenie ven-tilátora (pomenovanej VENTILATOR_REPAIRED). V reakcii na tútosprávu v scenári zastavte naplánované znižovanie energie Ripleyovej.

Pr riešení myslite na to, že premenné definované v rámci lambdynie sú viditel’né mimo lambdy a do lokálnych premenných defino-vaných mimo lambdy nemôžete prirad’ovat’ v rámci lambdy inéobjekty. Lokálne premenné zachytené v lambde sú totiž efektívnefinálne10. 10 https://docs.oracle.com/

javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variablesÚloha 4.8

Overte implementáciu celej misie.Po oprave ventilátora kladivom by Ripleyovej mala prestat’ klesat’

energia. Ak opravu nestihne do casu, ked’ jej energia klesne na 0,nemali by ste vediet’ Ripleyovú už ovládat’.

Doplnujúce zdroje

• Editor Tiled používaný na vytváranie herných máphttp://www.mapeditor.org/

• Návrhový vzor Abstract factoryhttp://en.wikipedia.org/wiki/Abstract_Factory_

pattern

• Metóda intersectsWithWall()

Page 101: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

IXIntricate Devices of Life and Death

MOTIVÁCIA

Situácia je naozaj kritická. Chvíl’ami to vyzeralo, že Ripleyová bude pokorená nástrahami objektovo-orientovaného sveta, no len vd’aka tvojej pomoci, kadet, môžeme konštatovat’, že ešte vykazuje známkyživota - má dostatok energie. Misia ešte nie je na konci, no máš plnú dôveru a podporu taktického a strate-gického tímu na jej úspešné dokoncenie. Hoci votrelcom nekoluje v žilách krv ale žieravá kyselina, tiežvykazujú známky života, takže musí existovat’ spôsob, ako ich porazit’. Ripleyová bude zrejme musiet’vyskúšat’ viacero zbraní, nielen tých ženských, aby zistila, co na tie nemilé kreatúry naozaj platí. V prvomrade ale jej život závisí na tvojom pláne, ako úcinne identifikovat’ všetkých živých nepriatel’ov.

Z operacného strediska zdraví Manager.

C IELE

1. Precvicit’ si použitie návrhového vzoru Observer.

2. Implementovat’ vlastné funkcionálne rozhranie.

3. Využit’ kompozíciu namiesto dedenia ("Composition over inheri-tance").

4. Využit’ návrhový vzor Dekorátor na kompozíciu správania aktérov.

Krok 1: They mostly come at night... Mostly.

Operacné stredisko získalo cerstvé satelitné snímky kolónie na planéteAcheron (LV_426). V oblasti boli spozorované zvláštne tvory doposial’neznámeho a evidentne mimozemského (rozumej extraterrestrial,skrátene E.T.) pôvodu. Zrejme sa vôbec nejedná o tie rozkošné Špíl-bergove stvorenia1, ktoré chcú íst’ domov. Kontakt s týmito zrejme 1 http://en.wikipedia.org/wiki/

E.T._the_Extra-Terrestrialnebude príjemný...

Úloha 1.1

Pripravte si mapu pre dnešnú misiu z adresy http://oop-kniha.

pages.kpi.fei.tuke.sk/edicia-2018/download/levels/

Page 102: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

94 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

<<abstract>>AbstractActor

<<interface>>Actor

<<interface>>Movable

Alien

Obr. IX.1: Trieda Alien a jej vzt’ahy kexistujúcim triedam a rozhraniam.

escape-room.zip do adresára src/main/resources/maps/v projekte, novú triedu pre scenár EscapeRoom a v nej vnorenúFactory triedu pre vytváranie aktérov na mape.

Patricne upravte metódu main(), aby ste mali v hre scénu s novoumapou, nastavenou inštanciou EscapeRoom.Factory ako actorfactory a EscapeRoom ako scene listener.

Úloha 1.2

Podl’a uvedeného diagramu vytvorte v balíku sk.tuke.kpi.oop.game.characters

triedu votrelca Alien.Trieda nech má (zatial’) bezparametrický konštruktor. Votrelec nech

je reprezentovaný spritom alien.png (Obr. IX.2).

Obr. IX.2: Animácia alien.png(rozmery sprite-u: 32x32, trvaniesnímku: 0.1).Úloha 1.3

Upravte EscapeRoom.Factory tak, aby ste vedeli vrátit’ objektyaktérov pre Ripleyovú, lekárnicku, zásobník nábojov a votrelca. 2 2 Otvorte si súbor mapy a pozrite si

mená a typy aktérov, ktorých budete pretúto misiu potrebovat’.

Úloha 1.4

Umožnite votrelcom, aby sa pohybovali náhodne.Trieda World, ktorú používate ako implementáciu scény, obsahuje

Topic pre pridávaných aktérov s názvom ACTOR_ADDED_TOPIC.Do tejto témy sú publikované správy vždy vtedy, ked’ je do scénypridaný nejaký aktér. Daný aktér je zároven obsahom poslanej správy.Túto tému využite na "odchytenie" pridávania votrelcov do scény anaplánujte im náhodný pohyb s využitím už existujúcich akcií.

Ked’že metóda scenára sceneInitialized() je volaná ažpo tom, co je mapa scény inicializovaná a aktéri v nej definovanívložení do scény, potrebujete sa prihlásit’ na odber správ z témyWorld.ACTOR_ADDED_TOPIC ešte predtým. Preto v rámci triedyscenára prekryte metódu sceneCreated(), ktorá bude zavolanáhned’ po vytvorení scény.

Page 103: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INTRICATE DEVICES OF LIFE AND DEATH 95

Úloha 1.5

Overte svoju implementáciu.Po spustení hry by ste mali vidiet’ mapu dnešnej misie, na ktorej by

už mala by umiestnená Ripleyová, niekol’ko predmetov a pobehujúcivotrelci.

Krok 2: Signs of (Half-)Life

Taktickému a strategickému tímu sa podarilo nabúrat’ do tajnýchzáznamov z utajovanej pitvy votrelcov a prekvapivo zistili, že ichexistencia závisí od životných funkcií, podobných ako u l’udí. Tak-tický a strategický tím teda navrhuje, aby si na reprezentáciu týchtoživotných funkcií vytvoril triedu Health, ktorá nahradí doterajšiepremenné pre energiu a zabezpecí väcšiu flexibilitu riešenia. Náš tímd’alej navrhuje, aby si aktérov, ktorí prejavujú známky života, odlíšilod ostatných prostredníctvom rozhrania Alive.

<<abstract>>AbstractActor

<<interface>>Actor

<<interface>>Alive Health

<<interface>>MovableRipley

Obr. IX.3: Ripleyová je živým aktérom.

Úloha 2.1

V balíku sk.tuke.kpi.oop.game.characters vytvorte trieduHealth.

Objekty triedy Health budú slúžit’ na uchovávanie hodnotyzdravia živých aktérov ako aj na manipuláciu s touto hodnotou.

Úloha 2.2

Vytvorte parametrický konštruktor pre triedu Health, ktorý ocakáva2 celocíselné parametre: pociatocnú hodnotu zdravia a maximálnuhodnotu zdravia.

Hodnoty oboch parametrov konštruktora uchovajte v stave triedy.

Page 104: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

96 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Ked’že budete potrebovat’ zist’ovat’ aktuálnu hodnotu zdravia, sprís-tupnite si ju pomocou getter metódy nazvanej getValue().

Castou situáciou bude nastavenie oboch parametrov konštruktorana rovnakú hodnotu, co bude znacit’, že aktér zacína s maximál-nym zdravím. Pre zjednodušenie použitia triedy v takomto prípadevytvorte v triede Health ešte jeden parametrický konštruktor sjedným celocíselným parametrom, ktorým nastavíte pociatocnú amaximálnu hodnotu zdravia na rovnaké hodnoty.

Úloha 2.3

Pridajte do triedy Health verejné metódy refill(), restore(),drain() a exhaust().

Signatúry metód a ich význam nech je nasledovný:

• void refill(int amount) - metóda navýši hodnotu zdraviao množstvo urcené parametrom. Samozrejme, výsledná hodnotanesmie presiahnut’ maximálnu hodnotu zadanú pri vytváraníobjektu.

• void restore() - metóda nastaví hodnotu zdravia na max-imálnu možnú.

• void drain(int amount) - metóda zníži hodnotu zdraviao množstvo urcené jej parametrom. Výsledná hodnota nesmieklesnút’ pod 0, co je už stav signalizujúci, že aktér vlastniaci danýobjekt zdravia sa úplne vycerpal a zomrel.

• void exhaust() - metóda spôsobí okamžité úplné vycerpaniezdravia, a teda nastaví hodnotu zdravia na 0.

Úloha 2.4

Podl’a vyššie uvedeného diagramu vytvorte v balíku ‘sk.tuke.kpi.oop.game.characters‘rozhranie Alive.

Rozhranie bude oznacovat’ živých aktérov a bude obsahovat’deklaráciu metódy ‘Health getHealth()‘, ktorá vráti referenciu naobjekt triedy Health asociovaný s daným aktérom.

Úloha 2.5

Upravte implementáciu Ripleyovej podl’a vyššie uvedeného diagramu,aby využívala nové rozhranie Alive a objekt triedy Health.

Upravte triedu Ripley, aby implementovala rozhranie Alive. Nezabudnite na to, že metódygetEnergy() a setEnergy(), ako ajs nimi súvisiacu clenskú premennú, užviac v triede Ripleyovej nepotrebujete.Takisto všetky miesta, kde ste doterazpoužívali spomínané metódy patricneupravte na použitie nových metódobjektu triedy Health.

Dalej zabezpecte vytvorenie objektu triedy Health v konštruktoretriedy Ripley. Pociatocnú aj maximálnu hodnotu zdravia nastavte na100.

Page 105: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INTRICATE DEVICES OF LIFE AND DEATH 97

Úloha 2.6

Aplikujte návrhový vzor Observer na situáciu, ked’ sa hodnota zdraviav objekte typu Health nejakého Alive aktéra vycerpá a dosiahnehodnotu 0. Využite funkciu akceptujúcu tzv. callback3. 3 https://en.wikipedia.org/

wiki/Callback_(computer_programming)

Z minulého cvicenia by ste mali mat’ v metóde setEnergy()okrem nastavenia energie aj test na dosiahnutie hodnoty 0, pri splneníktorého sa odošle správa o smrti Ripleyovej. Ked’že ale objekt triedyHealth nemá referenciu na vlastniaceho aktéra, nemôžete tútofunkcionalitu presunút’ do jeho metódy drain(). Preto pridámedo triedy Health metódu onExhaustion(), ktorá umožní na miestevolania registrovat’ akciu v podobe bloku kódu (funkcie), ktorý savykoná v momente dosiahnutia zdravia s hodnotou 0. Uvedomte si, že použitím tzv. callback-u

nerealizujete automaticky implementá-ciu návrhového vzoru Observer. Callbackje ale možné pri tomto vzore použit’ vsituáciách podobných tu opísanémupríkladu: blok kódu odovzdaný akocallback je použitý až v momente, ked’nastane udalost’, ktorá má byt’ observer-om spracovaná.

V našom prípade bude callback reprezentovat’ funkcia bez parametrova bez návratovej hodnoty. Nevýhodou jazyka Java je, že toto neviemezapísat’ priamo pomocou nejakého funkcionálneho typu. Namiestotoho musíme využit’ tzv. funkcionálne rozhranie: rozhranie, ktoré mápráve jednu abstraktnú metódu. Také rozhranie, nazvané Exhaus-tionEffect a obsahujúce metódu apply(), si aj vytvoríte. A ked’žetoto rozhranie budeme používat’ v konecnom dôsledku len v triedeHealth, vytvorte toto rozhranie ako vnorené práve v triede Healthnasledovne:

1 public class Health {

2 // ...

3

4 @FunctionalInterface

5 public interface ExhaustionEffect {

6 void apply();

7 }

8 }

Všimnite si anotáciu@FunctionalInterface vo uvede-nom príklade kódu. Nie je nevyhnutnána fungovanie funkcionálnych rozhraní,no zabezpecí vyvolanie chyby v prípade,že anotované rozhranie nebude mat’práve jednu abstraktnú metódu.

Takže, po príprave typu pre náš callback, spät’ k novej metódeonExhaustion(), ktorú je potrebné pridat’ do triedy Health. Tátometóda bude mat’ nasledovnú signatúru:

1 public void onExhaustion(ExhaustionEffect effect);

V tele metódy onExhaustion() pridajte objekt poskytnutý vparametri effect do zoznamu všetkých efektov, ktorý si v triedeHealh vytvoríte. Zoznam použite z toho dôvodu, aby bolo možnéviacnásobným volaním metódy onExhaustion() registrovat’ viacefektov vycerpania na tom istom objekte Health.

Page 106: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

98 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Následne upravte implementáciu metódy drain() tak, aby podosiahnutí hodnoty zdravia 0 došlo k postupnému zavolaniu metódyapply() na všetkých registrovaných efektoch. Využite metóduforEach() nad kolekciou efektov.

Nezabudnite na to, že aj v prípade volania metódy exhaust()

dôjde k úmrtiu aktéra a callback funkcie musia byt’ zavolané aj v tomtoprípade. Vhodne implementujte metódu exhaust(), aby ste sa vyhliduplicite kódu.

Pri implementácii zabezpecte, aby kvyvolaniu callback-ov došlo iba prvýkrátpri dosiahnutí hodnoty zdravia 0.

Úloha 2.7

Využite metódu onExhaustion() triedy Health na nakonfig-urovanie detekcie poklesu zdravia Ripleyovej na hodnotu 0 a pre-pošlite správu o jej smrti do zbernice správ na scéne.

Argument metódy onExhaustion() zapíšte pomocou lambdavýrazu:

1 health.onExhaustion(() -> {

2 // reakcia na vycerpanie zdravia

3 });

Zápis pomocou lambdy je ekvivalentný nasledovnému zápisupomocou anonymnej triedy, kde priamo na mieste volania metódyonExhaustion() implementujeme triedu ExhaustionEffect

s konkrétnou implementáciou metódy apply() a zároven z nejvytvoríme inštanciu. Takýto zápis by vyzeral nasledovne:

1 > health.onExhaustion(new Health.ExhaustionEffect() {

2 > @Override

3 > public void apply() {

4 > // implementacia metody

5 > }

6 > });

Pri implementácii reakcie Ripleyovejna nulovú hodnotu zdravia sa vámmôže zíst’ metóda cancelActions()dostupná na scéne, ktorou viete zrušit’všetky naplánované a prebiehajúceakcie asociované s aktérom, ktoréhoodovzdáte ako argument metódy.

Úloha 2.8

Zovšeobecnite triedu Energy tak, aby bola lekárnicka využitel’náakýmkol’vek Alive aktérom a nie iba Ripleyovou.

Page 107: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INTRICATE DEVICES OF LIFE AND DEATH 99

Krok 3: Know Your Enemy

V predošlom kroku ste vyškolili Ripleyovú ako sa má starat’ o svojezdravie, no už prišiel cas, aby sa popasovala so svojimi nepriatel’mi.Rozpozná ich vd’aka rozhraniu Enemy.

<<abstract>>AbstractActor

<<interface>>Actor

<<interface>>Movable

<<interface>>Enemy

<<interface>>AliveHealth

Alien

Obr. IX.4: Trieda Alien

Úloha 3.1

V balíku sk.tuke.kpi.oop.game.characters vytvorte podl’avyššie uvedeného diagramu prázdne rozhranie Enemy (marker inter-face), pomocou ktorého bude možné rozlišovat’ nepriatel’ov. Zatial’ jejediným nepriatel’om bežne sa vyskytujúci votrelec.

Úloha 3.2

Upravte triedu Alien tak, aby implementovala rozhranie Enemy aAlive.

Vykonajte aj všetky potrebné úpravy vyplývajúce z implementácierozhrania Alive.

Úloha 3.3

V metóde addedToScene() votrelca naplánujte znižovanie energiekaždému Alive aktérovi, ktorý zároven nie je Enemy, a ktorý prídedo kontaktu s votrelcom.

Page 108: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

100 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 3.4

Vytvorte triedu AlienMother pre matku votrelcov.Táto trieda bude rozšírením triedy bežného votrelca. Matka votrel-

cov bude mat’ vyššiu hodnotu maximálneho aj pociatocného zdraviaako ostatní votrelci, napríklad hodnotu 200.

Ako animáciu použite obrázok mother.png (Obr. IX.5).

Obr. IX.5: Animácia mother.png(rozmery sprite-u: 112x162, trvaniesnímku 0.2).

Úloha 3.5

Upravte továrenskú triedu pre vytváranie aktérov, aby vytvorilainštanciu aj pre matku alienov.

Matka votrelcov má meno "alien mother".

Obr. IX.6: Na palube sa nachádza prílišvel’a votrelcov

Krok 4: Lieutenant, what do those pulse rifles fire?

Ripleyová už efektívne zameriava nepriatel’ov, no to jej nepomôže,kým nemá úcinnú zbran. Hoci by sa neurazila, aj keby sme jej dorúk vložili obycajné pácidlo, ovel’a bezpecnejší je boj z dial’ky, a nato sa už žiada použit’ kvalitnú strelnú zbran. Predtým, ako všakRipleyovú vybavíte zbranou pomocou rozhrania Armed, musí prejst’expresným školením o zaobchádzaní so zbranami a strelivom, coumožní abstraktná trieda Firearm a rozhranie Fireable.

Page 109: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INTRICATE DEVICES OF LIFE AND DEATH 101

Ripley

Gun

<<interface>>Movable

<<abstract>>AbstractActor

<<interface>>Armed

<<interface>>Alive

Bullet

<<abstract>>Firearm

<<interface>>Fireable

<<interface>>Actor

Obr. IX.7: Ripleyová získava zbran

Úloha 4.1

V balíku sk.tuke.oop.game.weapons vytvorte abstraktnú trieduFirearm, ktorá bude definovat’ všeobecnú funkcionalitu strelnejzbrane.

Konštruktor triedy bude mat’ (podobne ako v prípade triedyHealth) 2 celocíselné parametre: pociatocný pocet nábojov v zbrani amaximálny možný pocet nábojov v zbrani.

Úloha 4.2

V triede Firearm implementujte verejné metódy getAmmo() areload().

Signatúry metód a ich význam nech je nasledovný:

• int getAmmo() - metóda vráti pocet momentálne dostupnýchnábojov.

• void reload(int newAmmo) - metóda zvýši pocet nábojovzbrane o hodnotu definovanú parametrom newAmmo. Hodnota saale môže zvýšit’ len natol’ko, aby neprekrocila maximálny pocetnábojov zbrane definovaný pri jej vytvorení.

Page 110: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

102 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 4.3

V balíku sk.tuke.kpi.oop.game.weapons vytvorte markerrozhranie Fireable podl’a vyššie uvedeného diagramu.

Rozhranie Fireable bude predpisom pre všetkých aktérov, ktoríbudú môct’ figurovat’ ako strelivo do zbrane.

Úloha 4.4

V balíku sk.tuke.kpi.oop.game.weapons vytvorte na základevyššie uvedeného diagramu triedu Bullet reprezentujúcu vystrelenýnáboj.

V metóde startedMoving() z rozhrania Movable nezabudnitenastavit’ správne otocenie animácie vystreleného náboja. Rýchlost’náboja nastavte napríklad na 4.

Ako animáciu reprezentujúcu náboj použite súbor bullet.png(Obr. IX.8). Obr. IX.8: Animácia bullet.png

(rozmery spritu: 16x16).

Úloha 4.5

Zabezpecte pohyb náboja Bullet a jeho odstránenie zo scény pozásahu.

Vystrelený náboj sa má po umiestnení do scény zacat’ pohybovat’ vdefinovanom smere a pokial’ zasiahne l’ubovol’ný objekt typu Alive,zníži jeho aktuálnu hodnotu zdravia o 10. Následne náboj zmizne zoscény. Pri kolízii so stenami (pevnými prekážkami) sa náboj tiež stratí.

Zatial’co kolíziu s Alive aktérmi je možné detegovat’ jednoduchopomocou ich metódy intresects(), pri zist’ovaní kolízie so stenounastáva problém. Takáto kolízia je totiž "skrytá" akciou Move (ktorúby mala trieda Bullet na pohyb využívat’) a mimo jej metódy ex-

ecute() ju nie je možné odsledovat’. Implementovat’ odstránenieobjektov Bullet do tejto metódy však nie je vhodné riešenie, pretožeporušuje princíp jednej zodpovednosti4 a zbytocne vnáša nežiaduce 4 https://docs.google.

com/open?id=0ByOwmqah_nuGNHEtcU5OekdDMkk

závislosti medzi triedami. Úlohu detekcie kolízie so stenou vyriešimenasledovne a pritom to riešenie zovšeobecníme pre všetkých Mov-

able aktérov.Do rozhrania Movable pridajte metódu collidedWithWall() so

štandardnou (default) prázdnou implementáciou:

1 public interface Movable extends Actor {

2 // ...

3

4 default void collidedWithWall() {}

5 }

Page 111: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INTRICATE DEVICES OF LIFE AND DEATH 103

Táto metóda bude pre Movable aktérov reprezentovat’ udalost’narazenia do steny. Preto ju potrebujete volat’ v akcii Move pri detekciikolízie so stenou. Prekrytím tejto metódy v triede Bullet potomviete dosiahnut’ požadované odstránenie náboja zo scény.

Úloha 4.6

Do triedy Firearm pridajte verejnú metódu fire() a protectedabstraktnú metódu createBullet().

Obe metódy budú bezparametrické a ich návratový typ budeFireable.

Metóda createBullet() je vyhradená na vytvorenie inštanciestreliva urceného pre danú zbran. Bude abstraktná a protected preto,lebo jej implementáciu - vytvorenie konkrétneho typu streliva - doplníkonkrétna zbran.

Metóda fire() má 2 možné priebehy:

• V prípade, že zbran ešte obsahuje náboje, ich pocet sa dekrementujea metóda vráti novú inštanciu streliva vytvorenú pomocou metódycreateBullet().

• Ak v zbrani už náboje nie sú, metóda vráti null.

Úloha 4.7

V balíku sk.tuke.kpi.oop.game.weapons vytvorte podl’a vyššieuvedeného diagramu triedu Gun, reprezentujúcu zbran, ktorú budepoužívat’ Ripleyová.

Konštruktor by mal mat’ dva parametre zodpovedajúce konštruk-toru nadtriedy.

Zbran bude vystrel’ovat’ náboje typu Bullet.

Úloha 4.8

V balíku sk.tuke.kpi.oop.game.characters vytvorte rozhranieArmed a upravte triedu Ripley tak, aby ho implementovala.

Rozhranie Armed bude identifikovat’ aktérov, ktorí majú zbran(majú referenciu na inštanciu triedy rozširujúcu Firearm), a budeobsahovat’ metódy na získanie a zmenu zbrane aktéra:

• Firearm getFirearm()

• void setFirearm(Firearm weapon)

Implementujte toto rozhranie v triede Ripley a zabezpecte, abyRipleyová mala k dispozícií zbran (Gun) hned’ po vytvorení jej inštan-cie.

Page 112: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

104 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Úloha 4.9

Zabezpecte, aby Ripleyová po stlacení tlacidla SPACE vystrelila. Natento úcel implementujte v balíku sk.tuke.kpi.oop.game.actions

akciu Fire a do balíka sk.tuke.kpi.oop.game.controllerspridajte ovládac ShooterController.

Akcia Fire má byt’ použitel’ná aktérom implementujúcim Armed

a má zabezpecit’ umiestnenie novej inštancie streliva použitej zbranedo scény a naplánovat’ pre neho "nekonecný" pohyb v smere otoceniaArmed aktéra pomocou akcie Move. Konštruktor akcie bude bezpara-metrický, ked’že pri implementácii si vystacíme s aktérom, na ktoromsa akcia naplánuje.

Pri implementácii budete potrebovat’ zistit’ smer pohybu (Direction)na základe uhlu otocenia aktéra. Na tento úcel vytvorte v enumeráciiDirection statickú metódu Direction fromAngle(float an-

gle).ShooterController bude mat’ parametrický konštruktor s

parametrom typu Armed, ktorý bude reprezentovat’ ovládanéhoaktéra. Plánovanie akcie Fire realizujte v metóde keyPressed() postlacení klávesy SPACE.

Úloha 4.10

Zovšeobecnite triedu Ammo tak, aby bol zásobník nábojov využitel’nýakýmkol’vek Armed aktérom a nie iba Ripleyovou.

Krok 5: Watch your behaviour! decorator

Hlavnou nástrahou pre Ripleyovú budú v tejto misii, samozrejme,votrelci, ktorí cíhajú za zavretými dverami. Udalost’ otvorenia dveríich však prebudí, následkom coho môže nastat’ zmätok. Aby sa alesituácia úplne nevymkla spod kontroly, bude tvojou úlohou, kadet,naucit’ skupiny votrelcov vhodne sa správat’. Zachovávajúc jednu zhlavných tém dnešnej misie, ktorou je composition over inheritance,t’a touto cast’ou prevedie náš taktický a strategický tím za pomocinávrhového vzoru Dekorátor.

Úloha 5.1

Upravte triedu Door tak, aby sa dala použit’ nielen pre vertikálne, aleaj pre horizontálne orientované dvere.

Do triedy Door pridajte enumeracný typ Orientation s hod-notami HORIZONTAL a VERTICAL, ktoré sa použijú na rozlíšenieorientácie dverí. Pridajte orientáciu dverí ako parameter konštruktora

Page 113: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INTRICATE DEVICES OF LIFE AND DEATH 105

Alien

<<interface>>Behaviour

Observing

RandomlyMoving

Obr. IX.9: Správanie aktérov

a na základe jeho hodnoty nastavte správnu animáciu (vdoor.pngresp. hdoor.png) pre dvere.

Obr. IX.10: Animácia vertikálnych dverívdoor.png (rozmery spritu: 16x32,trvanie snímku: 0.1)

Obr. IX.11: Animácia horizontálnychdverí hdoor.png (rozmery spritu:32x16, trvanie snímku: 0.1)Nezabudnite skontrolovat’, ci spôsob,akým vytvárate na mieste zatvorenýchdverí stenu, pracuje správne pre obeorientácie dverí. V prípade potreby houpravte.

Úloha 5.2

Pridajte dverám konštruktor so signatúrou Door(String name,

Orientation orientation), v ktorom bude možné definovat’okrem orientácie dverí aj ich názov.

Názov dverí odovzdajte ako argument konštruktoru nadtriedyAbstractActor.

Úloha 5.3

Upravte factory triedu tak, aby vytvárala správne orientované dverepre všetky dvere v mape.

Úloha 5.4

V novom balíku sk.tuke.kpi.oop.game.behaviours vytvorterozhranie Behaviour, ktoré bude reprezentovat’ predpis správaniasa aktérov vo forme akcií.

Rozhranie bude mat’:

• typový parameter, ktorým sa vymedzí, pre aký typ aktérov je danésprávanie aplikovatel’né,

• metódu bez návratovej hodnoty setUp(), ktorá dostane aktéraako parameter a ktorej úlohou bude definovat’ správanie sa danéhoaktéra.

Úloha 5.5

V balíku sk.tuke.kpi.oop.game.behaviours vytvorte trieduRandomlyMoving, ktorá bude reprezentovat’ správanie sa Movableaktéra - bude sa náhodne pohybovat’.

Page 114: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

106 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

Pomôžte si implementáciou náhodného pohybu aliena, ktorú byste mali mat’ v rámci scenára. Plánované akcie zovšeobecnite prel’ubovol’ného Movable aktéra.

Úloha 5.6

Triedam Alien a MotherAlien pridajte parameter konštruktoratypu Behaviour, ktorým bude možné definovat’ danému votrelcovijeho správanie.

Ked’že chceme mat’ možnost’ použit’ správania urcené pre typAlien a všetky jeho nadtypy (typy od ktorých Alien dedí, napr.Movable, Alive, atd’.), zapíšte signatúru parametra pre správanienasledovne:

1 Behaviour<? super Alien> behaviour

Získanú referenciu na objekt správania využite v metóde added-ToScene(), kde zavoláte jeho metódu setUp() na nastavenie sprá-vania sa daného votrelca.

Úloha 5.7

Upravte továren aktérov tak, aby ste pre votrelca typu "running"

odovzdali inštanciu správania RandomlyMoving.Pre ostatné typy votrelcom zatial’ nastavte správanie na null. Nezabudnite zrušit’ plánovanie náhod-

ného pohybu pre votrelcov v scenári.

Úloha 5.8

Overte svoju implementáciu.Votrelec s typom "running" by sa mal náhodne pohybovat’.

Ostatní votrelci by mali byt’ nehybní.

Úloha 5.9

V balíku pre správania vytvorte triedu Observing, ktorá budereprezentovat’ správanie aktéra, ktorý caká na publikovanie špeci-fickej správy (objektu s urcitými vlastnost’ami) do konkrétnej témyspráv.

Táto trieda správania bude slúžit’ ako dekorátor pre iné správanie. Návrhový vzor dekorátor je popísanýna stránke SourceMaking: https://sourcemaking.com/design_patterns/decorator

Zamýšl’ané použitie je nasledovné:ak aktér dostane v tomto správanízaobalené správanie náhodného pohybu,bude najskôr cakat’ na publikovanievyhovujúcej správy a až potom saaplikuje správanie, ktoré bolo zaobalené.

Ked’že trieda Observing bude zaobal’ovat’, resp. dekorovat’ inésprávanie, bude mat’ typový parameter (napr. A) pre typ aktérov, prektorých bude použité dekorované správanie vytvorené. Navyše, ked’žebude pracovat’ aj s nejakým typom tém správ, bude mat’ d’alší typovýparameter (napr. T) pre objekty posielané v správach:

Trieda bude mat’ konštruktor s troma nasledovnými parametrami:

Page 115: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

INTRICATE DEVICES OF LIFE AND DEATH 107

1 public class Observing<A extends Actor, T> implements Behaviour<A> {

2 // ...

3 }

• Topic<T> topic - téma správ, ktorú bude aktér sledovat’

• Predicate<T> predicate - predikát (podmienka) na overenieprijatej správy

• Behaviour<A> delegate - zaobalené správanie

V metóde setUp() sa prihláste na odoberanie témy správ topic,pricom po jej prijatí skontrolujte podmienku definovanú predikátompredicate a v prípade jej splnenia zavolajte setUp() metóduzaobaleného správania delegate.

Rozhranie Predicate<T>5 je štandardné funkcionálne rozhranie 5 https://docs.oracle.com/javase/10/docs/api/java/util/function/Predicate.html

urcené na testovanie podmienok. Definuje jednu abstraktnú metódutest(), ktorej parameter je typu T.

Zamýšl’ané použitie správania Observing je teda možné de-monštrovat’ na nasledovnom príklade. Ak by sme chceli votrelcovidefinovat’ správanie, kedy po použití zásobníka nábojov (bude odstrá-nený zo scény) zacne prenasledovat’ Ripleyovú (ak by sme na to malidefinované správanie napr. ChasingRipley), zapísali by sme tonasledovne:

1 new Alien(

2 new Observing<>(

3 World.ACTOR_REMOVED_TOPIC,

4 actor -> actor instanceof Ammo,

5 new ChasingRipley()

6 )

7 );

Úloha 5.10

Zabezpecte "prebudenie" spiacich votrelcov po otvorení dverí domiestnosti, v ktorej sa nachádzajú.

Prebudením votrelcov sa myslí to, že sa zacnú náhodne pohybovat’.Využite vytvorené triedy správaní na definovanie správania votrel-

cov, ktorí majú v mape definované typy "waiting1" a "waiting2".Majú reagovat’ na otvorenie dverí s menami "front door", resp.

Page 116: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav

108 OBJEKTOVO-ORIENTOVANÉ PROGRAMOVANIE : PRÍPADOVÁ ŠTÚDIA PRE CVICENIA

"back door". Správanie, samozrejme, potrebujete definovat’ už priich vytváraní v factory triede.

Úloha 5.11

Overte svoju implementáciu.Votrelci v jednotlivých miestnostiach by sa mali zacat’ hýbat’ po

tom, co Ripleyová otvorí príslušné dvere.

Úloha 5.12

Hru ukoncite, ked’ Ripleyová otvorí dvere, ktoré majú v mape defino-vané meno "exit door".

Ukoncenie hry môžete reprezentovat’ napríklad vypísaním ne-jakého textu (napr. Well done!) do Overlay6 vrstvy hry.

6 http://oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/javadoc/sk/tuke/kpi/gamelib/graphics/Overlay.html

Doplnujúce zdroje• Java Tutorial: Annonymous Classes

https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html

• Callback: odovzdávanie vykonatel’ného kódu ako argument volania funkcie, wikipedia.orghttps://en.wikipedia.org/wiki/Callback_(computer_programming)

• Lambda výrazy: wikipedia.orghttps://en.wikipedia.org/wiki/Anonymous_function

• Návrhový vzor pozorovatel’ (observer):wikipedia.orghttps://en.wikipedia.org/wiki/Observer_pattern,sourcemaking.comhttp://sourcemaking.com/design_patterns/observer

• Návrhový vzor dekorátor (decorator):wikipedia.comhttps://en.wikipedia.org/wiki/Decorator_pattern,sourcemaking.comhttp://sourcemaking.com/design_patterns/decorator

Page 117: Objektovo-orientované programovanie: Prípadová štúdia pre ...oop-kniha.pages.kpi.fei.tuke.sk/edicia-2018/download/oop-ps-2018.pdf · Ján Juhár, Jana Št’astná, Miroslav