TDDE10 Objektorienterad programmering i Java
Textbaserat Spel - OOP i java
Tips innan du startar labben
Laborationens bakgrund och återkoppling från tidigare års studenter
Detta är en stor lab. Vi vet att studenter historiskt lagt väldigt mycket tid på denna laboration: både före redovisning och efter med åtskilliga stora kompletteringar.
Det är delvis för att den pedagogiska grundprincipen för laborationen är att man får utforska vad som kan göras och sedan får återkoppling av assistent. Vi vill att ni skall komma in i ett nytt objektorienterat tänk.
Vi erbjuder också ett stabilt tips: Om man inte gör detta på ett objektorienterat sätt, så tar det mycket längre tid, eftersom varje tillägg i koden medför många förändringar på många ställen. Om man istället gör snygga klasser, med bra inkapsling och som utnyttjar arv och polymorfi till sin fördel så har man igen detta grundarbete senare, och tillägg/förändringar i koden går mycket snabbt att implementera. Det är detta som är den stora poängen men laborationen.
Alltså, om ni kommer till ett läge där ni känner "GUUU va mycke det är! Aja, vi köttar på och lägger in fem if-satser till här" så är ni troligtvis inte rätt ute. Ta då ett par steg tillbaka, reflektera över hur ni delar upp problemet i klasser och vilken klass som får anvsara för vad. Ibland behöver man ta ett par steg tillbaka för att sedan kunna köra vidare frammåt. Detta kallas med ett finare ord för "refaktorering".
Andra tips:
- Läs igenom hela uppgiften innan ni börjar. Försök att få ett tydlig och klar bild vad ni ska göra och skapa er en idé om hur ni kan åstadkomma detta.
- Rita! Rita hur ni vill att er karta ska se ut och vilka platser som hänger ihop. Skapa bilder att referera till senare.
- Välj ett eget tema på uppgiften. Är temat roligt för er kommer det bli roligare att implementera det senare.
Inledning
Börja självklart med att läsa igenom hela laborationshandledningen så att du får en översikt över laborationens struktur och omfång och vad som ska göras och hur det ska redovisas.Laborationen går ut på att lära sig grunderna för objektorienterad programmering, samt motsvarande språkkonstruktioner i Java.
Laborationen består av olika steg där du får öva på bl.a. följande begrepp inom OOP:
Följande begrepp inom OOP introduceras:
- Klasser och instanser
- Konstruktorer
- Arv
- Polymorfism
- Instansvariabler och klassvariabler (static-variabler)
- Metoder och klassmetoder (static-metoder)
- Inkapsling och "information hiding" (skydda implementationen)
- Skyddsnivåerna private, protected, public
- Ansvar, (d.v.s. vilken klass skall göra vad?)
Problembeskrivning
Året är 1989 och företaget PCGamez har anställt dig för att skapa ett äventyrsspel. Vad detta innebär (kom ihåg att detta är 1989) är ett datorspel där en spelare manövrerar runt i en påhittad värld, träffar på saker, människor, monster och andra underliga ting, via ett textuellt gränssnitt. Spelet går ut på att försöka ta sig till en specifik plats och/eller utföra en särskild handling och/eller ha ett visst (antal) föremål. Några mer kända sådana äventyrsspelen är Adventure och Zork.
Generella Krav:
- Alla klasser skall ha konstruktorer som tar lämpliga parametrar (data som man inte borde få skapa objektet utan).
- Alla klasser bör ha sina instansvariabler privat. Det behövs goda själ för att t.ex. sätta instansvariabler till public eller protected. Om data behöver kommas åt eller ändras utifrån klassen bör detta göras via s.k. getters resp. setters.
- Deklarera variabler så lokalt som möjligt. Variabler som bara behöver finnas inuti en metod skall deklareras där, inte vara instans-/klassvariabler.
- När det gäller arv och klasshirarkier, fundera noga över vad som är gemensamt för subklasserna och lägg detta i superklassen. Missar man detta så får man ofta kodduplicering.
- Stora if- eller switch-satser indikerar ofta att man inte tänker på ett objektorienterat sätt. Skapa istället individuella klasser för det som skall variera och uppnå olika beteende m.h.a. polymorfi. Därmed är det inte förbjudet att använda if-satser, de kommer att behövas på många ställen.
- Fundera på vad som behöver vara en egen klass och vad som endast kan vara instanser av en generell klass. Om du får många klasser som är exakt lika, bortsätt från vilka data de lagrar så kan du ju använda en gemensam klass, som du instansierar med olika data.
- Om en klass börjar bli för stor så kan det vara för att den har för mycket ansvar. Dela upp i mindre klasser och låt dem ansvara för mindre delar.
- Vissa klasser skall vara abstrakta, vilka då? Vad innebär det? Varför just dessa klasser?
- Tänk över huruvida en metod skall vara en klassmetod (d.v.s static) eller inte. Metoder som inte behöver en instans av klassen de befinner sig i görs med fördel till klassmetoder. (Detta är dock inte normalfallet i objektorienterad programmering, då man nästan alltid "befinner sig i" ett objekt.)
- Tänk på huruvida en variabel skall vara en klassvariabel (d.v.s static) eller inte. Tillhör den ett specifikt objekt, eller hela klassen?
Del A - Grundläggande funktionalitet (Game, Player, Location, o.s.v.)
Första delen av UML-diagrammet:
Tänk på att detta är ett förslag från PCGamez. Du kanske inte behöver alla egenskaper hos dessa klasser och det kommer förmodligen att behövas många fler metoder och variabler/parametrar än vad som ritats ut ovan (och eventuellt även fler klasser).
I denna första del av laborationen skall du implementera klasserna Game, Player, Location (och dess subklasser). Efter att denna del är klar skall man kunna spela spelet. Man kommer dock endast att kunna gå mellan olika platser.
Viktigt! Välj ett tema för spelet som passar er labbgrupp. Om det är roligt att arbeta med laborationen går det lättare att lära sig, och snabbare att komma framåt.
Exempel på hur spelet kan se ut när man spelar det:
(Det som matats in av användaren är i fet och kursiverad stil.)Welcome to the adventure game! What is your name? Nathalie Hello Nathalie, welcome to this magical world of wonder! You can move around by typing north/south/west/east. You will have to learn more commands as you play the game! (Hint: there is a command "help"). You are standing in the middle of a plain. It seems to go on for miles and miles. You cannot remember how you got here and you have nothing but the clothes on you. Way out in the distance to the north you see some mountains. Over to the east you see some trees. The sun is pale and a cool breeze caresses your skin. There is a road leading north. There is a road leading east. What do you want to do? east You wander into what seems to be an old forest of oak trees. Something unnerves you as you tip toe forward, trying not to stir whatever is resting here. Suddenly you are in a small clearing and there is a big boar in front of you! The boar is blocking the path. There is a road leading west. What do you want to do? west You are out on the plain again. There is a road leading north. There is a road leading east. What do you want to do?
Kravlista
Funktionella krav (krav på funktionalitet):- Det skall finnas åtminstone fem platser som världen består av. Ha åtminstone en av vardera typen som visas i klassdiagrammet, men du får skapa egna subklasser.
- Spelaren skall ha ett namn som får väljas i början av spelet.
- Se till att det finns ett kommando "help" som ger spelaren lite anvisningar om hur man spelar.
- Spelaren skall hålla reda på sin nuvarande plats och kunna gå mellan olika platser (m.h.a. kommando "north"/"west"/"south"/"east").
- Spelet skall inte krascha om man försöker gå åt ett otillåtet håll.
- Alla platser (Location-objekt) har en längre och en kortare beskrivning. Den längre beskrivningen används bara första gången platsen besöks.
- Det skall finnas två olika typer av platser, rum och utomhusplatser. Skillnaden är att rum beskriver kopplingen till andra platser som dörrar medan utomhusplatser kallar sina kopplingar för vägar. Dessutom har utomhusplatser väder som kan ändras under spelets gång.
- Klassen Game skall skapa världen i sin konstruktor.
- Game-objektet skall hålla reda på spelaren, och ha en samling med alla spelets Location-objekt.
- Klassen Game skall ha en metod run som innehåller själva spel-loopen.
- Alla platser kan ha upp till fyra kopplingar till andra platser.
- Platser skall ha en metod describeYourself låter platsobjekten själva bestämma hur de skall presenteras. Denna metod kan överskuggas i alla objekt som ärver från klassen Location.
- Platser, Game och Spelaren har även metoden doCommand som låter objekten själva bestämma vad som händer då användaren använder ett visst kommando. Tänk noga över vilka parametrar dessa metoder kan behöva, det kommer inte räcka med bara det som står i diagrammet.
- Det skall vara mycket enkelt att för någon som inte är insatt i resten av koden att lägga till nya platser och till och med nya typer av platser, (t.ex. Rum med dolda dörrar). Optimalt sett bör man bara behöva ärva från rätt klass och sedan göra ett tillägg i den befintliga koden. Om ni behöver ändra i många filer (ofta i stora if-satser) för att lägga till ny funktionalitet tyder detta på att ni inte har löst det på ett objektorienterat sätt.
Kodskelett
public class Main { public static void main(String[] args) { Game g = new Game(); g.run(); } }Game.java
import java.util.*; public class Game { private Scanner keyboard; private ArrayList<Location> locations; private Player player; public Game() { keyboard = new Scanner(System.in); locations = new ArrayList<>(); locations.add(new Location("Starting location")); } public void run() { String name; System.out.println("Welcome to the adventure game!\nWhat is your name?"); name = keyboard.nextLine(); player = new Player(name, locations.get(0)); System.out.println("Hello " + name + ", welcome to this magical world of wonder!" + " You can move around by typing north/south/west/east." + " You will have to learn more commands as you play the game!" + " (Hint: there is a command \"help\")."); while (true) { String command; player.getLocation().describeYourself(); System.out.println("What do you want to do?"); command = keyboard.nextLine(); player.doCommand(command); } } }
Del B - Föremål (Item, Tool, WearableItem)
Körexempel
What do you want to do? items You have the following items: shovel (2.1 kg) elven_robe (3 kg) torch (1 kg) What do you want to do? wear elven_robe You put on the elven_robe. What do you want to do? dig You dig a hole in the ground, but you find nothing here. What do you want to do? look You are out on the plain again. There is a road leading north. There is a road leading east. What do you want to do? north You come to a cave in the mountains. Your torch shines red light on the stone walls. You can now see that there is a path at the back of the cave, but you have no idea where it leads. There is a bone from a large animal on the floor. There is a door leading west. What do you want to do? take bone You picked up the bone. What do you want to do?
Kravlista
Funktionella krav:- WearableItems kan man ta på sig och ger oftast någon effekt (mer hälsa, skydd av något slag, vissa NPC:er beter sig annorlunda). Man skall kunna ta på sig saker med kommandot "wear".
- Normalt sett skall alla föremål som finns på en plats skrivas ut när spelaren besöker den platsen.
- För att användaren skall kunna veta vilka föremål den har ska den kunna skriva "items", då skall spelet lista dem, och vad man har på sig för tillfället.
- När det nu börjar bli lite mer att göra för spelaren så kan det vara bra för den att ha ett sätt att åter få reda på vad som fanns på platsen (vägar/dörrar, saker i rummet), lägg därför till kommandot "look" som skriver ut dessa saker igen.
- När man vill plocka upp ett föremål som ligger i ett rum skall man använda kommandot "take".
- Det skall finnas minst fem föremål i spelet. Vi rekommenderar shovel (som man kan gräva och hitta saker med), elven_robe (som man kan ta på sig), och torch (som lyser upp rum som annars är mörka). Hitta på två helt egna föremål också.
- Du kanske kommer fram till att du behöver ändra lite i tidigare klasser. Hur ser du till att framtida tillägg kommer kräva minimal (eller ingen) förändring i den nuvarande koden?
- Klassen Item skall vara en superklass som alla andra föremål ärver ifrån. Den innehåller gemensamma attribut för alla föremål (namn, vikt och pris).
- Item skall ha en metod doCommand som definierar vad föremålet kan göra (eller tillåta att spelaren gör). Tänk noga över vilka parametrar den metoden behöver.
- Det skall finnas minst två subklasser till Item: Tool och WearableItem. (Weapon implementeras i del C).
- Tool är klassen (eller snarare superklassen) för diverse verktyg, t.ex. spaden. Tools definierar själva vilket kommando man behöver skriva för att använda dem i metoden use. Det är därför inte konstigt om alla Tools blir egna klasser, som ärver av klassen Tool.
- WearableItem är klassen (eller snarare superklassen) för diverse kläder, t.ex. elven_robe. WearableItems definierar själva vad som händer när man anropar metoden putOn(). Det är därför inte konstigt om alla föremål blir egna klasser, som ärver av klassen WearbleItem.
Tänk på att detta är ett förslag från PCGamez (för del A och del B). Det kommer förmodligen att behövas många fler metoder och variabler/parametrar än vad som ritats ut ovan (och fler klasser också).
Del C (Frivillig men bonusgivande) - Varelser (NPC, Monster, Person, Weapon)
You are in the oak woods, in the clearing. There is a big boar in front of you! The boar is blocking the path. There is a road leading west. What do you want to do? kill boar The boar charges straight at you! Luckily you have your spear, you would not have survived the attack without it. Now that the boar is gone you see another path in front of you to the east. What do you want to do? east You arrive at a small hut at the edge of the forest. In front of the hut is a small old man sitting on the ground. He appears to be begging as he has a bowl in front of him, with a few coins therein. There is a road leading west. There is a road leading south. There is a road leading north. What do you want to do? give coins The man's bushy eyebrows are raised and you can see the wisdom in his aged eyes. He tells you "Nathalie, seek the altar on the mountain summit, and place this gem thereupon. You will then find your true purpose!". You got strange_gem from beggar. What do you want to do?
Kravlista
Funktionella krav:- Normalt sett skall spelet alltid skriva ut vilka NPC:er som finns på en plats då spelaren besöker platsen.
- Det skall finnas minst tre NPC:er i spelet. Vi rekommenderar vildsvinet (boar), beggar och en egenpåhittad NPC till spelet.
- Klassen NPC skall vara en superklass som alla andra varelser ärver ifrån. Den innehåller gemensamma attribut för alla föremål (namn, hälsa och föremål).
- Det skall åtminstone finnas två typer av NPC:er: Monster och Person.
- Monsterklassen skall ha en metod attack som bestämmer vad som händer då spelaren attackerar monstret (eller tvärt om).
- Personklassen har istället metoden interactWith som bestämmer vad som händer då spelaren interagerar med personen.
- Lägg till klassen weapon, och instansen spear, så att spelaren har en chans mot vildsvinet.
Tänk på att detta är ett förslag från PCGamez (för del A-C). Det kommer förmodligen att behövas många fler metoder och variabler/parametrar än vad som ritats ut ovan. NPC står för non-player character och representerar varelser som inte kontrolleras av spelaren.
Del D (Frivillig men bonusgivande) - Finishing Touches
Ditt spel är nu så pass bra att du nästan kan sälja det och tjäna storkovan, åtminstone tills Doom kommer ut. Det som behövs är ett par "finishing touches".
För att få Del D:s bonus krävs det att ni lagt in tre eller fler av de förslag som finns i listan nedan. Har ni egna liknande ideér på saker som bör ge bonus måste ni få dessa godkända av Emma eller Magnus innan ni gör dem.
I er Game-klass ska också en javadoc-kommentar skapas som beskriver vilka tre ni valt och i vilken klass de finns.
Förslag på "finishing touches"
- En häftig feature är att även låta NPC:erna få agera i spelet. Lägg till i spelets huvudloop ett steg där en metod hos NPC:erna anropas där de själva kan bestämma vad de skall göra.
- En annan typ av NPC man kan lägga till är en som rör sig mellan spelets platser. Detta kan antingen vara genom en interaktion med spelaren eller så kan den röra sig av sig själv.
- Skapa en eller fler hemliga platser som man endast kan ta sig till genom en hemlig dörr eller genom att låsa upp den genom att spela spelet.
- Gör så att man kan sälja och köpa items i utbyte mot guld. Detta kan vara genom en försäljnings-NPC eller något annat smart ni kommer på.
- Uppgradera ert inventory så att det är vikt-känsligt. Man kan bara ha med sig items upp till en specifik vikt och går vikten över detta måste man kasta ett item för att plocka upp ett annat.
- Uppgradera vädret så att detta förändras under spelets gång.
- Uppgradera rummens storlek så att viss funktionalitet enbart kan ske i vissa storlekar på rum. Detta kan vara att man till exempel bara kan träna svärdfäktning i stora rum, eller bara sova i små rum.
- Uppgradera items så att de endast kan användas ett antal gånger.
- Lägg till funktionalitet i Player. Detta kan vara utseende som påverkar interaktioner med NPC:er, eller kanske att spelaren har ett rykte som kan förändras under spelets gång.
- Lägg till så att man kan vinna eller förlora spelet. Det kan t.ex. vara att ta sig till en specifik plats (som förmodligen inte är helt trivial att ta sig till), eller att man skall få tag i något visst föremål, eller besegra ett visst monster, eller en kombination av ovanstående. På liknande sätt kanske man förlorar om dör mot monster. Vilken klass bör ansvara för att hålla reda på vad spelaren har utfört?
Sidansvarig: Magnus Nielsen
Senast uppdaterad: 2024-01-10