Rogue101/SEM-1_DEL-A.md
Anya Helene Bagge 14ed39ad7b updates
2018-02-28 15:29:13 +01:00

18 KiB
Raw Blame History

Semesteroppgave 1: “Rogue One oh one” Del A: Bakgrunn, modellering og utforskning

Kunnskap/konsepter du har bruk for til denne delen

  • Abstraksjon å se bort fra uvesentlige detaljer og konsentrere seg om de tingene som er viktig (for det vi holder på med / fra vårt synspunkt)
  • Modellering en modell er en (som regel forenklet) representasjon av noe. Vi bruker modeller for å
    • prøve ut / leke med / teste ting når vi ikke kan/vil gjøre direkte med det vi modellerer (f.eks.: en klimamodell lar oss forstå hvordan klimaet kan utvikle seg i forskjellige scenarier uten at vi trenger å teste det i virkeligheten; en prototype lar deg se hvordan at produkt kan bli; en modell lar deg se hvordan klær ser ut uten å måtte prøve dem på deg selv; et dataspill lar deg gjøre ting du ikke kunne gjort (eller hatt lov til) i virkeligheten; lek lar barn bygge “romskip” og utføre medisinsk behandling på “spedbarn” uten å svi av plenen eller skade lillebror).
    • ha et eksempel som vi kan bruke når vi skal lage flere ting (f.eks.: kilogramprototypen, arkitekttegninger, 3D designmodeller (CAD/CAM))
  • Objekter (new C()) med oppførsel (metoder) og innkapslet tilstand (feltvariabler), og relasjoner til og interaksjon med andre objekter.
  • Interface (interface I, class C implements I) hvordan du kan bruke objekter som du har (og hvilke metoder objektenes klasse må implementere)

Ting som (kanskje) er nytt:

  • interface I extends J både I og J må være grensesnitt
    • Alle metodene i J er også med i I (som om du hadde listet dem opp i I)
    • I blir en subtype av J hvis noe er en I (er av en klasse som implementerer I) så kan det også brukes som en J (i en variabel av type J, f.eks.). (Det motsatte er ikke tilfelle ikke alle J-er er I-er.)
  • default-metoder i interface/grensesnitt disse gir deg kode for en metode så du slipper å implementere den selv i klassen din.
    • Default-metodene har ikke tilgang til feltvariabler, og de kan bare bruke metodene i grensesnittet.
    • Typiske default-metoder er ekstrametoder som bygger på de andre metodene (metoder som er praktisk for bruk uten å være helt nødvendige). Det er også praktisk når man senere skal legge til flere metoder i et grensesnitt, for å slippe å måtte oppdatere en hel haug med klasser.

Rogue 101

Semesteroppgaven er en naturlig videreutvikling av Labyrint-oppgaven i stedet for å bare gå rundt i en kjedelig labyrint, skal vi nå kunne gå rundt, plukke opp ting og interagere med ting.

Bakgrunn

Et eksempel på et slikt labyrint-spill er Rogue, som er et gammel dungeon crawl-spill med “tekst-grafikk”, der du går rundt i en labyrint, plukker opp ting og dreper monstre. De første slike spillene dukket opp på slutten av 1970-tallet; Rogue (1980) var et av de første, og har gitt navn til hele sjangeren (“Roguelike”). Dungeon crawls og roguelike spill har vært veldig populære opp gjennom tidene (ikke minst på grunn av fancy 2D-grafikk med tekst-symboler, som var et betydelig steg opp fra tidligere adventure/fantasy spill som hvor alt var bare tekst), inkludert gamle klassikere som NetHack, Moria og Larn. Ofte har disse spillene vært laget som hobbyprosjekter av programmører (informatikk-studenter, for eksempel) og vært mer kompliserte (og mye vanskeligere) enn spill fra kommersielle spillprodusenter, selv om de gjerne ikke har hatt spesielt fancy grafikk.

Moderne roguelike spill (og moderne utgaver av de gamle) kommer gjerne med mer fancy grafikk og er ofte laget av uavhengige utviklere. I de litt bredere kategoriene “dungeon crawls” og “adventure” finner du en haug med vanlige, populære spill f.eks. Zelda-serien (startet i 1986 med “gå rundt på et 2D-grid/kart, plukk opp ting, sloss med monstre og løs puzzles”; de nyeste versjonene tilbyr en åpen 3D-verden med detaljert fysikk, grafikk og lyd).

Vi har tenkt å holde det relativt enkelt (mer som 1980 enn som 2020), siden det antakelig er få av dere som er fulltids spilldesignere/spillprogrammører (og om du er det, har du neppe tid til å gjøre denne semesteroppgaven!). “Rogue101” (du kan selvfølgelig finne på et eget navn) skal

  • være turn-based dvs., spillet venter på at spilleren skal gjøre et trekk
  • foregå på et todimensjonalt rutenett/kart basert på samme måte som Labyrint-labben, og sett ovenfra / i fuglepersektiv
  • ha ting som spilleren kan plukke opp / gjøre noe med / legge fra seg
  • ha andre aktører som går rundt på samme kartet og er styrt av datamaskinen (f.eks., monstre, kaniner, flyvende regnbueenhjørninger, zombier, amerikanske politikere, etc)

Om du nå er fristet til å gjøre litt “research”problemdomenet, så trenger du ikke det oppgaven kommer med beskrivelse av reglene du skal implementere, og en del tips til mulige varianter. I siste del av semesteroppgaven kan du designe ting sånn som du selv har lyst til. Ellers så får du gjerne litt ideer selv etterhvert som du blir kjent med systemet. (Det er altså ikke et mål å lage en kopi av Rogue eller et annet spill, og ting trenger overhodet ikke ha noe med dungeons, monstre og sverd å gjøre du kan f.eks. lage spill der du er korrupt saksbehandler i et kontorlandskap som må plukke opp alle sakspapirene og putte de i makuleringsmaskinen før FBI-agenten tar deg...)

original game screen shot

Oversikt Modellering

Vi kan tenke på programmet vårt som en “modell” av et dungeon crawler spill. For å finne ut hvilke klasser og interfaces vi trenger, må vi

  • a) først tenke oss hvilke elementer som inngår i spill-verdenen;
  • b) finne ut hvordan vi representerer og implementerer disse på datamaskinen.

Dette er likende til prosessen vi snakket om på de første forelesningene:

  1. Vi har et problemdomene, dungeon crawling
  2. Vi analyserer domenet, og lager en abstrakt beskrivelse av det, f.eks. spillreglene skrevet på papir.
  3. Vi designer programmet, og prøver å lage en konkret implementasjon.
  4. Vi tester programmet vårt mot forventingene, og justerer på ting og gjentar prosessen.

Mesteparten av denne jobben er allerede gjort for deg. Din jobb er nå å sette deg inn i koden og vår dungeon crawling modell. Vi har gjort analyse og design og en god del implementasjon, så vi er ca. på slutten av punkt 3. Du må bli kjent med koden og komfortabel med å gjøre endringer, og så gå videre med implementasjonen. I siste del av oppgaven er det du som er “sjefen”, og kan gjøre (nesten) som du vil med design og regler.

Analyse hva er de essensielle bitene av Rogue-101?

Basert på tidligere erfaringer med slike spill, samt grunding tenking og lesing av de relevante Wikipedia-sidene, ser vi for oss følgende:

  • Alt foregår på et ruteformet kart (2D grid)
  • Hver celle/rute på kartet kan inneholde enten:
    • en vegg
    • 0 eller flere ting
  • En “ting” i denne sammenhengen er:
    • et objekt som spilleren/noen kan plukke opp og bruke til noe f.eks. en gulrot, et papirark, et sverd, en brunostskive, osv.
    • eller en aktør en “levende” ting som kan bevege seg rundt på kartet
  • For enkelhets skyld sier vi at det bare kan være maks én aktør i hver kartrute men en aktør kan dele plass med andre ting.
  • Aktørene er enten styrt av datamaskinen, eller styrt av spilleren.
  • For å gjøre ting litt mer spill-aktig, har vi følgende regler for ting og aktører
    • alle ting (inkl aktører) har “helse-poeng” som indikerer i hvor god form/stand aktøren/tingen er; negative helsepoeng betyr at tingen er helt ødelagt og skal fjernes fra brettet
    • alle ting (inkl aktører) har “forsvars-poeng” som indikerer hvor god den er til å forsvare seg (mot å bli angrepet, plukket opp, vasket bak ørene, e.l.)
    • alle aktører har "angreps-poeng" som indikerer hvor god den er til å overgå andres forsvar (og f.eks. skade dem, plukke dem opp, vaske dem bak ørene, e.l.)
    • merk deg at alle ting har helse og forsvar, selv ting som er ikke er levende dette kan vi f.eks. bruke til å gjøre det mulig å ødelegge ting eller gjøre enkelte ting vanskelige å plukke opp

Design hvordan lager vi dette i Java?

Basert på dette tenker vi oss følgende typer objekter:

  • [IMapView](src/inf101/v18/rogue101/map/IMapView.java], [IGameMap](src/inf101/v18/rogue101/map/IGameMap.java] spillkartet
  • IItem en ting. Siden både småobjekter (sverd og gulrøtter), aktører og vegger er ting som befinner seg på kartet, er det praktisk å gjøre alle til IItem.
    • Wall en IItem som ikke kan dele plass med noe annet
    • IActor en IItem som bevege seg og ikke kan dele plass med en annen IActor
      • IPlayer en IActor som styres ved at brukeren trykker på tastene
      • INonPlayer en IActor som styrer seg selv (datamaskinen styrer)

Vi har også et par andre mer abstrakte ting vi bør tenke på f.eks. koordinater. Det går an å bruke heltall som koordinater / indekser (int x, int y), men det er generelt ganske praktisk med en egen abstraksjon for grid-plasseringer; blant annet kan vi da slippe å gjøre kompliserte utregninger på koordinatene for å finne frem til andre koordinater. Vi har derfor også:

  • ILocation en lovlig (x,y)-koordinat på kartet. Hver ILocation har opptil åtte andre ILocations som naboer, og har metoder for å finne alle eller noen av naboene, og for å finne nabo i en spesifikk retning.
  • GridDirection en retning (NORTH, SOUTH, ...), til bruk sammen med ILocation
  • IArea et rektangulært sett med ILocations. Brukes f.eks. av spillkartet for å lettvint gå gjennom alle cellene/rutene i kartet.
  • (IGrid og IMultiGrid IGrid er tilsvarende til den du har brukt i labbene tidligere; IMultiGrid er et grid der hver celle er en liste av T-er. Den blir brukt av spillkartet, men du trenger neppe bruke den selv.)

Deloppgave A1: Tilstand, oppførsel og grensesnitt for objektene

*Du vil sikkert finne på lurere svar på spørsmålene etterhvert som du jobber med oppgaven. Det er fint om du lar de opprinnelige svarene stå (det er helt OK om de er totalt feil eller helt på jordet) og heller gjør tilføyelser. Du kan evt. bruke overstryking (putt dobbel tilde rundt teksten, ~~Rabbit.java funker fordi det bor en liten kanin inni datamaskinen~~) for å markere det du ikke lenger synes er like lurt.

Alle grensesnittene beskriver hvordan du kan håndtere objekter (objekter som er av klasser som implementerer grensesnittene). Selv om tilstanden til objektene er innkapslet (du vet ikke om feltvariablene), så lar metodene deg observere tilstanden, så ut fra de tilgjengelige metodene kan du spekulere litt rundt hvordan tilstanden må være.

Les gjennom grensesnittene vi har nevnt over (IGameMap, IItem, IActor, INonPlayer, IPlayer vent med å se på klassene) og svar på spørsmålene (skriv svarene i README.md, det holder med én eller noen få setninger):

  • 1. Hva vil du si utgjør tilstanden til objekter som implementerer de nevnte grensesnittene? (F.eks. hvis du ser på ILocation så vil du gjerne se at ILocation-objekter må ha en tilstand som inkluderer x- og y-koordinater selv om de sikkert kan lagres på mange forskjellige måter)

  • 2. Hva ser ut til å være sammenhengen mellom grensesnittene? Flere av dem er f.eks. laget slik at de utvider (extends) andre grensesnitt.

  • 3. Det er to grensesnitt for kart, både IGameMap og IMapView. Hvorfor har vi gjort det slik?

  • 4. Hvorfor tror du INonPlayer og IPlayer er forskjellige? Ville du gjort det annerledes?

Deloppgave A2: Eksempler på IItem og IActor

Til denne deloppgaven kan du se først på Carrot og Rabbit. Svar på spørsmålene (skriv svarene i README.md, det holder med én eller noen få setninger):

  • 5. Stemmer implementasjonen overens med hva du tenkte om tilstanden i Spørsmål 1 (over)? Hva er evt. likt / forskjellig?

Se på Game og GameMap også.

Rabbit trenger å vite hvor den er, fordi den skal prøve å spise gulroten (hvis den finner en) og fordi den må finne seg et gyldig sted å hoppe videre til.

  • 6. Hvordan finner Rabbit ut hvor den er, hvilke andre ting som er på stedet og hvor den har lov å gå?

  • 7. Hvordan vet Game hvor Rabbit er når den spør / hvordan vet Game hvilken Rabbit som kaller getLocation()?

Deloppgave A3: Litt endringer

  • Du kan kjøre programmet ved å kjøre inf101.v18.rogue101.Main. Hendige tastetrykk (du skal få lov å legge til flere selv senere):
    • Return gjør ett steg (selv om vi foreløpig ikke har en IPlayer på brettet)
    • Ctrl-Q / Cmd-Q avslutt
    • F11 eller Ctrl/Cmd-F bytt til/fra fullskjerm
    • Ctrl-R / Cmd-R bytt mellom forskjellige varianter av 40- og 80-tegn tekstskjerm

Hvis du kjører programmet og trykker litt på returtasten vil du se at kaninene (merket med r) hopper rundt litt, at gulrøttene (oransje dingser med grønn topp) forsvinner og at kaninene så etterhvert forsvinner.

Smart kanin

Hvis du ser på koden for Rabbit.java finner du gjerne også ut hvorfor ting oppfører seg slik: kaninenes helse er avhengig av at de finner noe å spise, og bevegelsene er helt tilfeldige. Prøv ut noen forskjellige endringer:

  • a) Juster maksimale helsepoeng på kaninene (evt. også på gulrøttene), og om du merker noen forskjell (husk at programmet foreløpig ikke gjør noe før du trykker retur/enter)
  • b) La kaninene alltid gå i samme retning (f.eks. game.move(GridDirection.NORTH kommenter ut den gamle koden). Prøv ut hva som skjer når de treffer vegger.
  • c) En annen mulighet er å alltid gå i første tilgjengelige retning; dvs. samme som den opprinnelige implementasjonen, men plukk første retning i stedet for en tilfeldig en. Prøv dette. Ser det ut som de blir bedre eller dårligere til å finne gulrøtter?
  • d) En enda bedre strategi er å sjekke alle nabofeltene, se om det ligger en gulrot der, og såfall gå dit (hvis den ikke ser en gulrot kan den f.eks. gå tilfeldig). Implementer dette. Tips:
    • når du har funnet ut hvilke retninger (GridDirection) du kan gå i, kan du finne nabofeltene med ILocation loc = game.getLocation(dir) (evt game.getLocation().go(dir)).
    • du kan finne ut hva som ligger i nabofeltet ved hjelp av kartet (game.getMap()); f.eks. med metoden getItems().
    • kaninen har allerede kode for å sjekke gjennom tingene og se om den finner en Carrot du kan kopiere og tilpasse denne
    • hvis kaninen finner en gulrot kan den gjøre game.move(...) og så returnere med en gang

Bedre gulrøtter

Prøv også å justere gulrøttene litt (Carrot):

  • a) Gulrøttene får helsen satt til -1 når de blir spist etter helsereglene våre vil de derfor bli fjernet fra kartet. Prøv å sette helsen til 0 i stedet. Hvorfor går det ikke bedre med kaninene selv om gulrøttene nå blir værende på kartet?
  • b) Det hadde kanskje vært praktisk (ihvertfall for kaninene) om gulrøttene vokste seg store og fine igjen etter en stund; for eksempel ved at de “helbreder” ett helsepoeng for hver runde som går men Carrot har ingen doTurn() metode slik Rabbit har, så den får ikke med seg at rundene går eller at kaninene hopper rundt (rent bortsett fra at det går an å “jukse” ved å regne med / håpe på at draw() blir kalt en gang per runde).
    • Lag en doTurn()-metode i Carrot som øker hp med 1 for hver runde (opp til getMaxHealth()).
    • Hva skjer, ser det ut til å virke?
    • Hvis det ikke virker, hva må du eventuelt gjøre for å få Carrot til å gjøre noe hver runde?
  • c) Du kan også prøve å la Game legge til nye, tilfeldig plasserte gulrøtter av og til:
    • random.nextInt(100) < 20 er en grei test hvis du f.eks. vil gjøre noe med 20% sannsynlighet
    • For å finne en tilfeldig ILocation kan du bruke map.getLocation(x, y) med tilfeldig x og y (innenfor getWidth()/getHeight()). Du kan også plukke et tilfeldig element fra map.getArea().locations().
    • Før du evt. putter en new Carrot() på kartet må du også passe på at kartruten du har funnet er ledig (ihvertfall at den ikke inneholder en vegg).

Deloppgave A4: Oversikt

Tegn en liten oversikt over det du tenker er de viktigste grensesnittene/klassene i programmet.

  • Hvis noe implements/extends noe, tegn en pil til det det implementerer/utvider.
  • Du kan skrive ned f.eks. de viktigste metodenavnene eller noen stikkord om rollen til den aktuelle typen.
  • Tegn også en liten oversikt over objekter i forskjellige situasjoner (f.eks. Rabbit, Carrot, Game, GameMap og hvordan de (evt) kommuniserer når kaninen holder på å gjøre noe).

(Du trenger ikke legge ved tegningen din, men du kan gjerne lage og legge ved en oppdatert utgave når du har fått bedre/full forståelse av systemet.)

Deloppgave A5: Ting du ikke trenger å se på (0/100)

  • Du trenger ikke se på koden i gfx (grafikkbibliotek), grid (utvidet IGrid) eller util (generering av testdata).
  • Hvis du lager grafikk selv, vil du gjerne komme til å bruke ITurtle (fra gfx), men du trenger ikke se på implementasjone.
  • GameMap gjør bruk av grid-pakken, men du trenger antakelig ikke gjøre noe med den selv.

Gå videre til Del B

SEM-1_DEL-B