Problemset 2: Project Ellen

Ciele

  • Implementovať vlastný herný level.
  • Implementovať vlastných actorov.
  • Navrhnúť a implementovať vlastnú funkcionalitu objektovo orientovaným spôsobom.
  • Identifikovať a použiť návrhové vzory vo vlastnom riešení.

Znenie zadania

Vytvorte jeden hrateľný level hry s využitím knižnice GameLib (verzia 2.4.2) v jazyku Java. Pre jej grafickú reprezentáciu môžete použiť sprity z počítačovej hry Alien Breed. Mapu levelu vytvorte pomocou editora Tiled. Level musí byť dohrateľný a pre jeho riešenie musí byť potrebné využiť sadu adventúrnych krokov. To znamená, že level nemôže byť lineárne dohrateľný len streľbou do nepriateľov, ale musí obsahovať predmety, s ktorými je potrebné interagovať.

Požiadavky na riešenie sú detailne opísané nižšie.

Pri práci na zadaní dodržiavajte etický kódex!

Dôležité termíny

  • Zadanie je potrebné odovzdať do systému GitLab najneskôr do nedele 16. decembra 2018.
  • Hodnotenia projektov systémom Arena budú prebiehať denne každé 2 hodiny. Posledné hodnotenie prebehne v nedeľu 16. decembra 2018 o 20:00. Áno, o 20:00.
  • Po úspešnom automatizovanom testovaní sa dostavíte na ústnu obhajobu vášho riešenia. Termín obhajoby je na cvičení v 13. týždni semestra.

Upozornenie

Ústna obhajoba je povinná na získanie bodov za druhé zadanie. Obhajovať budete môcť len kód, ktorý prešiel testami v Arene, teda kód posledného hodnotenia.

Poznámka

Testovanie v Arene je spustené od 9.12.2018 16:00.

Požiadavky na vaše riešenie

Pre úspešné odovzdanie zadania je potrebné splniť nasledovné požiadavky.

Funkčnosť a hrateľnosť

Projekt odovzdaný na GitLab-e musí byť kompletný a spustiteľný príkazom ./gradlew run (Linux, Mac OS) respektíve gradlew.bat run (Windows).

Poznámka

Projekt musí byť uvedeným spôsobom spustiteľný aj na inom ako vašom počítači.

Hra musí byť úspešne dohrateľná. Samotný koniec (záverečný, no nie jediný krok hry) však môže byť dosiahnuteľný rôznym spôsobom, ako napríklad: zničenie všetkých nepriateľov (alebo finálneho boss-a), opustenie úrovne konkrétnymi dverami alebo výťahom, stlačenie spínača alebo množiny spínačov, a podobne.

Vlastná mapa levelu

Je potrebné vytvoriť vlastnú mapu herného levelu s názvom map.tmx, ktorej plocha bude minimálne 500 dlaždíc - tiles (napríklad 20 x 25) ale nie väčšia ako 6400 dlaždíc (napr. 80 x 80). Viac o mape úrovne nižšie.

Mapu levelu vytvorte podľa tutoriálu pre integráciu s knižnicou GameLib.

Vlastní actori

V hre vytvorte minimálne 7 vlastných tried, ktoré budú implementovať rozhranie Actor, resp. rozširovať abstraktnú triedu AbstractActor. Dodržujte pri tom nasledovné požiadavky:

  • Tieto triedy a z nich vytvorené inštancie budú potrebné pre úspešné dosiahnutie cieľa hry, t.j. budú aktívne zapojené do scenára hry. Príkladom aktívneho zapojenia do scenára je použitie skrinky, otvorenie dverí, presunutie tehly na spínač v podlahe a podobne.
  • Nesmie sa jednať o prázdnych actorov - nesmú obsahovať len animáciu (konštruktor) bez žiadneho ďalšieho kódu (bez metód).
  • Do stanoveného počtu sa nezarátajú actori, ktorých implementácia bola úlohou prvého zadania (napríklad reaktor, chladič, kladivo, atď) a ktorí sú povinnou súčasťou hry (ich zoznam je uvedený nižšie). Taktiež sa nezarátajú actori s rovnakým správaním a vlastnosťami, ako boli uvedení v rámci hlavných úloh cvičení.

Použitie návrhových vzorov

V hre použite minimálne 4 návrhové vzory. Vyberajte si vzory prednostne zo skupín štrukturálnych a behaviorálnych návrhových vzorov. Takisto je možné využiť vzory Builder a Prototype zo skupiny vytváracích (creational) návrhových vzorov.

Upozornenie

K potrebným štyrom sa budú počítať len vaše vlastné použitia návrhových vzorov, nie tie implementované na základe úloh v cvičeniach.

Programátorský štýl

Pri programovaní dodržujte nasledovné zásady:

  • Na predmete Objektovo orientované programovanie je vyžadované riešenie, ktoré je písané objektovo - využívajte zapuzdrenie údajov, hierarchiu tried, rozhrania, kompozíciu, polymorfizmus. Bonusom sú vhodne použité vlastné typové parametre zovšeobecňujúce vaše riešenie.
  • Vytvárajte triedy s čo najmenším počtom členských premenných (členské premenné by mali byť len tie, ktoré sú nevyhnutné pre zaznamenanie stavu objektov!) s užitočným a zrozumiteľným API vo forme verejných metód. Metódy, ktoré riešia implementačné detaily, definujte ako privátne.
  • Predchádzajte duplikovaniu funkcionality.
  • Formátujte svoj kód podľa zaužívaných pravidiel pre jazyk Java.
  • Dbajte na pomenovanie identifikátorov (názvy tried, metód, premenných ...). Pomenovania majú byť zmysluplné a majú dodržiavať konvencie pre jazyk Java.

Pri testovaní vašeho riešenia v Arene bude vyžadované:

Upozornenie

Váš kód bude na Arene kompilovaný s prepínačmi -Xlint:unchecked,rawtypes -Werror, ktoré varovania ohľadom použitia unchecked operácii alebo raw typov skonvertujú na chyby a ich výskyt tak spôsobí zlyhanie kompilácie.
Tieto prepínače si viete nastaviť aj pre lokálnu kompiláciu kódu upravením existujúcej konfigurácie JavaCompile úloh v súbore build.gradle.kts do nasledovnej podoby:
tasks.withType<JavaCompile>().configureEach {
    options.compilerArgs.plusAssign(listOf("-parameters", "-Xlint:unchecked,rawtypes", "-Werror"))
}

Povinná časť implementácie (hodnotená testami)

Nasledovné triedy (signatúry ich konštruktorov) a rozhrania s definovanými metódami sú povinnou súčasťou vášho riešenia a budú sa hodnotiť testami v Arene:

  • actions:
    • trieda Drop<A extends Actor> (rozširuje AbstractAction)
      • konštruktor public Drop()
    • trieda Fire<A extends Armed> (rozširuje AbstractAction)
      • konštruktor public Fire()
    • trieda Move<A extends Movable> (implementuje Action)
      • konštruktor public Move(Direction direction, float duration)
      • metóda public void stop()
    • trieda Shift (rozširuje AbstractAction)
      • konštruktor public Shift()
    • trieda Take<A extends Actor> (rozširuje AbstractAction)
      • konštruktor public Take(Class<A> takableActorClass)
    • trieda Use<A extends Actor> (rozširuje AbstractAction)
      • konštruktor public Use(Usable<A> usable)
      • metóda public Disposable scheduleOnIntersectingWith(Actor mediatingActor)
  • behaviours:
    • rozhranie Behaviour<A extends Actor>
      • metóda void setUp(A actor)
    • trieda Observing<T, A extends Actor> (implementuje Behaviour)
      • konštruktor public Observing(Topic<T> topic, Predicate<T> predicate, Behaviour<A> delegate)
    • trieda RandomlyMoving (implementuje Behaviour)
      • konštruktor public RandomlyMoving()
  • characters
    • trieda Alien (rozširuje AbstractActor; implementuje Movable, Alive a Enemy)
      • konštruktor public Alien()
      • konštruktor public Alien(int healthValue, Behaviour<? super Alien> behaviour)
    • rozhranie Alive (rozširuje Actor)
      • metóda Health getHealth()
    • rozhranie Armed (rozširuje Actor)
      • metóda Firearm getFirearm()
      • metóda void setFirearm(Firearm firearm)
    • rozhranie Enemy (rozširuje Actor)
    • trieda Health
      • konštruktor public Health(int initHealth, int maxHealth)
      • konštruktor public Health(int initHealth)
      • metóda public int getValue()
      • metóda public void refill(int amount)
      • metóda public void restore()
      • metóda public void drain(int amount)
      • metóda public void exhaust()
      • metóda public void onExhaustion(ExhaustionEffect effect)
      • rozhranie ExhaustionEffect
        • metóda void apply()
    • trieda Ripley (rozširuje AbstractActor; implementuje Alive, Armed, Keeper a Movable)
      • konštruktor public Ripley()
      • statická premenná public static Topic<Ripley> RIPLEY_DIED
  • controllers:
    • trieda CollectorController (implementuje KeyboardListener)
      • konštruktor public CollectorController(Keeper<Collectible> collector)
    • trieda MovableController (implementuje KeyboardListener)
      • konštruktor public MovableController(Movable actor)
    • trieda ShooterController (implementuje KeyboardListener)
      • konštruktor public ShooterController(Armed shooter)
  • items:
    • trieda Ammo (rozširuje AbstractActor, implementuje Usable)
      • konštruktor public Ammo()
    • trieda Backpack (implementuje ActorContainer)
      • konštruktor public Backpack(String name, int capacity)
    • rozhranie Collectible (rozširuje Actor)
    • trieda Energy (rozširuje AbstractActor, implementuje Usable)
      • konštruktor public Energy()
    • rozhranie Usable<A extends Actor>
      • metóda void useWith(A actor)
      • metóda Class<A> getUsingActorClass()
  • openables:
    • trieda Door (rozširuje AbstractActor, implementuje Openable a Usable)
      • enumerácia Orientation { VERTICAL, HORIZONTAL }
      • konštruktor public Door(String name, Orientation orientation)
      • statická premenná public static Topic<Door> DOOR_OPENED
      • statická premenná public static Topic<Door> DOOR_CLOSED
    • rozhranie Openable (rozširuje Actor)
      • metóda void open()
      • metóda void close()
      • metóda boolean isOpen()
  • weapons:
    • trieda Bullet (rozširuje AbstractActor, implementuje Fireable)
      • konštruktor public Bullet()
    • rozhranie Fireable (rozširuje Movable)
    • abstraktná trieda Firearm
      • konštruktor public Firearm(int initAmmo, int maxAmmo)
      • konštruktor public Firearm(int initAmmo)
      • metóda public int getAmmo()
      • metóda public void reload(int amount)
      • metóda public Fireable fire()
      • abstraktná metóda protected Fireable createBullet()
    • trieda Gun (rozširuje Firearm)
      • konštruktor public Gun(int initAmmo, int maxAmmo)
  • enumerácia Direction
    • hodnoty NONE, NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST
    • konštruktor Direction(int dx, int dy)
    • metóda public int getDx()
    • metóda public int getDy()
    • metóda public float getAngle()
    • metóda public Direction combine(Direction other)
    • statická metóda public static Direction fromAngle(float angle)
  • rozhranie Keeper<A extends Actor> (rozširuje Actor)
    • metóda Actorcontainer<A> getContainer()
  • trieda Main
    • statická metóda public static void main(String[] args)
  • rozhranie Movable (rozširuje Actor)
    • metóda int getSpeed()
    • metóda default void startedMoving(Direction direction) {}
    • metóda default void stoppedMoving() {}
    • metóda default void collidedWithWall() {}

Poznámka

Vaša implementácia má byť postavená na tomto povinnom základe, aj keď nie je nevyhnutné, aby ste z neho využívali úplne všetko. V prípade potreby môžete uvedené triedy rozšíriť o vlastné metódy, ak zachováte funkcionalitu tých existujúcich.

Upozornenie

Uvedené povinné rozhrania nesmiete vo svojom riešení nijako modifikovať! Testy v Arene sú kompilované voči tu popísaným podobám rozhraní a v prípade, že vaše rozhrania im nebudú zodpovedať, môže sa stať, že testy, ktoré testujú alebo nejako využívajú dané rozhranie, sa nepodarí inicializovať.

Upozornenie

Kvôli testovaniu požadovaných troch ovládačov v balíku sk.tuke.kpi.oop.game.controllers je potrebné, aby ste zachovali priradenie kláves pre jednotlivé akcie tak, ako je to opísané v cvičeniach. V prípade, že si chcete priradenie kláves prispôsobiť, spravte to len pridaním ďalšej akceptovanej klávesy pre určitú akciu, aby ostali akceptované aj tie klávesy z cvičení.

Odovzdávanie

Zadanie sa odovzdáva prostredníctvom systému na správu verzií Git na školskom GitLab serveri https://git.kpi.fei.tuke.sk. Názov Git projektu musí byť project-ellen-2018.

Poznámka

Používajte ten istý projekt, ktorý ste používali pri prvom zadaní. Triedy požadované v rámci prvého testovania už testované nebudú. Podmienkou je len to, aby projekt ako celok bol skompilovateľný pomocou vyššie spomínaných prepínačov kompilátora, a aby všetky nestatické členské premenné boli privátne.

Štruktúra projektu

Štruktúra vášho projektu project-ellen-2018 s uvedeným umiestnením povinných častí implementácie musí vyzerať nasledovne:

. // root adresar repozitara
├── gradle  // obsahuje subory nastroja gradle
├── src
│  ├── main
│  │  ├── java
│  │  │  └── sk
│  │  │     └── tuke
│  │  │        └── kpi
│  │  │           └── oop
│  │  │              └── game
│  │  │                 ├── actions
│  │  │                 │  ├── Drop.java
│  │  │                 │  ├── Fire.java
│  │  │                 │  ├── Move.java
│  │  │                 │  ├── Shift.java
│  │  │                 │  ├── Take.java
│  │  │                 │  └── Use.java
│  │  │                 ├── behaviours
│  │  │                 │  ├── Behaviour.java
│  │  │                 │  ├── Observing.java
│  │  │                 │  └── RandomlyMoving.java
│  │  │                 ├── characters
│  │  │                 │  ├── Alien.java
│  │  │                 │  ├── Alive.java
│  │  │                 │  ├── Armed.java
│  │  │                 │  ├── Enemy.java
│  │  │                 │  ├── Health.java
│  │  │                 │  └── Ripley.java
│  │  │                 ├── controllers
│  │  │                 │  ├── CollectorController.java
│  │  │                 │  ├── MovableController.java
│  │  │                 │  └── ShooterController.java
│  │  │                 ├── items
│  │  │                 │  ├── Ammo.java
│  │  │                 │  ├── Backpack.java
│  │  │                 │  ├── Collectible.java
│  │  │                 │  ├── Energy.java
│  │  │                 │  └── Usable.java
│  │  │                 ├── openables
│  │  │                 │  ├── Door.java
│  │  │                 │  └── Openable.java
│  │  │                 ├── scenarios  // obsahuje triedy scenarov
│  │  │                 ├── weapons
│  │  │                 │  ├── Bullet.java
│  │  │                 │  ├── Fireable.java
│  │  │                 │  ├── Firearm.java
│  │  │                 │  └── Gun.java
│  │  │                 ├── Direction.java
│  │  │                 ├── Keeper.java
│  │  │                 ├── Main.java
│  │  │                 └── Movable.java
│  │  └── resources
│  │     ├── maps
│  │     │  ├── tilesets // obsahuje pouzite tilesety z mapy
│  │     │  └── map.tmx  // mapa vasho levelu hry
│  │     └── sprites  // obsahuje pouzite sprity actorov
├── .editorconfig
├── .gitignore
├── build.gradle.kts
├── gradlew
├── gradlew.bat
├── README.md
└── settings.gradle.kts

Poznámka

Súbory vytvorené v rámci vašeho vlastného levelu hry umiestňujte podľa potreby buď do niektorého z uvedených balíkov, alebo vytvorte vhodne pomenované a organizované nové balíky. Zachovajte však balík sk.tuke.kpi.oop.game ako rodičovský balík všetkých tried a rozhraní v projekte.

Upozornenie

Kódovanie všetkých odovzdávaných súborov musí byť UTF-8. Pri názvoch vytváraných súborov a priečinkov záleží na veľkosti písmen! Je dôležité, aby sa povinné súbory nachádzali na uvedených miestach v projekte, inak dôjde k zlyhaniu testov pre konkrétne súbory, ktoré sa nenájdu.

Obsah súboru README.md nech má nasledovný tvar:

GROUP: 01

Poznámka

Hodnota GROUP uvádza vašu skupinu, ktorú navštevujete na cvičeniach. To, ktorú skupinu navštevujete, si skontrolujte v rozvrhu predmetu v systéme MAIS.

Upozornenie

Informácia pre opakujúcich
Opakujúci študenti by mali do súboru README.md uviesť číslo skupiny z nasledujúceho zoznamu, podľa toho, ktorý študijný program študujú:
  • Informatika a Počítačové modelovanie: skupina 31
  • Hospodárska informatika a Inteligentné systémy: skupina 32

Závislosti projektu

Pri preklade a testovaní projektu budú predpokladané nasledovné nastavenia závislostí v súbore build.gradle.kts:

val gamelibVersion = "2.4.2"

dependencies {
    implementation("sk.tuke.kpi.gamelib:gamelib-framework:$gamelibVersion")
}

Hodnotenie

Za zadanie môžete získať max. 30 bodov. Z toho je 10 bodov vyhradených na hodnotenie automatickými testami a 20 bodov na obhajobu zadania.

Automatickými testami (10 bodov) bude v systéme Arena hodnotená povinná, spoločná časť funkcionality hry.

Pri obhajobe zadania (20 bodov) sa bude vaša implementácia hodnotiť:

  • z pohľadu používateľa-hráča (max. 6 bodov)
    • funkčnosť a hrateľnosť
    • prítomnosť adventúrnych krokov
    • počet actorov zapojených do hry
    • vizuálna stránka (bonus)
  • z programátorského pohľadu (max. 14 bodov)
    • programátorský štýl (~6 bodov)
    • použitie návrhových vzorov (~8 bodov)

Samozrejmosťou je, že študent vie odpovedať na otázky týkajúce sa odovzdávaného projektu. V prípade hraničného hodnotenia je možné očakávať doplnkové programátorské úlohy na rozšírenie alebo modifikáciu hry ako súčasť obhajoby.