11. týždeň

Problemset 2: Project Ellen

Ciele

  1. Implementovať vlastný herný level.
  2. Implementovať vlastných aktérov.
  3. Navrhnúť a implementovať vlastnú funkcionalitu objektovo orientovaným spôsobom.
  4. 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.6.1) 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. Základnú funkcionalitu hry implementujte podľa úloh z cvičení 7 až 10. Vlastný level hry 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ý napr. len streľbou do nepriateľov alebo pozbieraním nejakých premetov, ale musí obsahovať aktérov, 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ť (obe časti) do systému GitLab najneskôr do stredy 13. decembra 2023, 23:59.
  • Hodnotenia projektov systémom Arena budú prebiehať denne každé 3 hodiny. Posledné hodnotenie prebehne v stredu 13. decembra 2023 o polnoci.
  • Po úspešnom automatizovanom testovaní sa dostavíte na ústnu obhajobu vlastnej hernej časti vášho riešenia (ktorá nemôže byť pokrytá testami v Arene). Termín obhajob je na cvičeniach v 12. a 13. týždni semestra.

Upozornenie

Ústna obhajoba je nutná na možnosť získania plného počtu bodov za zadanie. V prípade, že nespravíte vlastnú hernú časť a vyriešite len základné úlohy pokryté testami v systéme Arena, nemá zmysel, aby ste na túto obhajobu prišli. Na obhajobe je možné získať len body vyhradené pre vlastnú hernú časť zadania.

1. Základná časť implementácie (hodnotená testami)

Nasledovné triedy (signatúry ich konštruktorov) a rozhrania s definovanými metódami reprezentujú stav základnej implemetácie po vypracovaní všetkých úloh cvičení 7 - 10 a budú sa hodnotiť testami v Arene:

  • actions:
    • trieda Drop<K extends Keeper> (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<K extends Keeper> (rozširuje AbstractAction)
      • konštruktor public Shift()
    • trieda Take<K extends Keeper> (rozširuje AbstractAction)
      • konštruktor public Take()
    • trieda Use<A extends Actor> (rozširuje AbstractAction)
      • konštruktor public Use(Usable<A> usable)
      • metóda public Disposable scheduleForIntersectingWith(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 onFatigued(FatigueEffect effect)
      • rozhranie FatigueEffect
        • 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 KeeperController (implementuje KeyboardListener)
      • konštruktor public KeeperController(Keeper keeper)
    • 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 NORTH, EAST, SOUTH, WEST
    • konštruktor Direction(int dx, int dy)
    • metóda public int getDx()
    • metóda public int getDy()
    • metóda public float getAngle()
    • statická metóda public static Direction fromAngle(float angle)
  • rozhranie Keeper (rozširuje Actor)
    • metóda Backpack getBackpack()
  • 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() {}
  • trieda SpawnPoint (rozširuje AbstractActor)
    • konštruktor public SpawnPoint(int spawnAliens)

Poznámka

Vaša implementácia má byť postavená na tomto základe, aj keď nie je nevyhnutné, aby ste z neho vo vlastnej hre 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í.

2. Požiadavky na vlastnú hernú časť zadania

Pre možnosť získať plný počet bodov za zadanie je potrebné vytvoriť už spomínaný hrateľný level. Pri obhajobe zadania sa bude kontrolovať splnenie nasledovných požiadaviek.

2.1 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. Myslite preto aj na zahrnutie všetkých obrázkov spritov a máp do projektu na GitLab-e.

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.

2.2 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.

2.3 Vlastní aktéri

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 aktérov - nesmú obsahovať len animáciu (konštruktor) bez žiadneho ďalšieho kódu (bez metód).
  • Do stanoveného počtu sa nezarátajú aktéri, 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ý vyššie). Taktiež sa nezarátajú aktéri s rovnakým správaním a vlastnosťami, ako boli uvedení v rámci úloh cvičení.

2.4 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é implementácie návrhových vzorov, nie tie implementované na základe úloh v cvičeniach.

2.5 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.

3. Testovanie

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> {
        options.compilerArgs.addAll(listOf("-parameters", "-Xlint:unchecked,rawtypes", "-Werror"))
    }
}

4. 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.

Používajte ten istý projekt, ktorý ste si vytvorili prostredníctvom aplikácie OOP Gitlab Classroom na začiatku semestra, a ktorý ste používali aj 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.

4.1 Štruktúra projektu

Štruktúra vášho projektu 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
│  │  │                 │  ├── KeeperController.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
│  │  │                 └── SpawnPoint.java
│  │  └── resources
│  │     ├── maps
│  │     │  ├── tilesets // obsahuje pouzite tilesety z mapy
│  │     │  └── map.tmx  // mapa vasho levelu hry
│  │     └── sprites  // obsahuje pouzite sprity akterov
├── .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.

4.2 Závislosti projektu

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

val gamelibVersion = "2.6.1"

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

5. Hodnotenie

Za zadanie môžete získať max. 30 bodov. Z toho je 15 bodov vyhradených na hodnotenie základnej časti automatickými testami a 15 bodov na obhajobu vlastnej hernej časti zadania.

Automatickými testami (15 bodov) bude v systéme Arena hodnotená základná časť funkcionality hry.

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

  • z pohľadu používateľa-hráča (max. 5 bodov)
    • funkčnosť a hrateľnosť
    • prítomnosť adventúrnych krokov
    • počet aktérov zapojených do hry
    • vizuálna stránka (bonus)
  • z programátorského pohľadu (max. 10 bodov)
    • programátorský štýl (~4 bodov)
    • použitie návrhových vzorov (~6 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.

Vaše riešenia prejdú kontrolou originality. Preto sa pri práci na vašom zadaní správajte podľa pravidiel etického kódexu! V prípade, že odovzdáte zadanie, ktoré nie je vaše, budete vylúčení z predmetu!