OO Textbased Game

Text-gebaseerd spel mbv OO technieken

De prijs voor meest sexy titel gaan we niet winnen. Maar naar de aloude traditie van de klassieke tekst-gebaseerde adventure-games (zie hier ) zullen we een eenvoudig object georiënteerd framework maken dat ons toelaat snel onze eigen games te maken. De nadruk van dit artikel ligt daarbij niet tot het creëren van een perfecte imitatie, maar wel om aan te tonen dat met een beetje object georiënteerde inzichten we tot zeer propere, herbruikbare én onderhoudbare code kunnen komen.

We maken uiteraard het spel in een Console-applicatie.

Main

We willen de Main() methode van Program.cs zo leeg mogelijk laten. Daarom zullen we de meeste functionaliteit verpakken in een klasse GameManager. Het enige dat we dan nog hoeven te doen in onze main is een loop starten die steeds 3 zaken zal doen:

  1. Huidige locatie beschrijven

  2. Aan gebruiker tonen welke acties hij kan uitvoeren

  3. Gewenste actie van gebruiker verwerken en uitvoeren

In code behelst dit:

static void Main(string[] args)
{
    Console.WriteLine("Welkom bij AP Adventure. Een avontuur voor moedige en minder moedige studenten. Ben je er klaar voor?");
 
    GameManager theGame= new GameManager();
 
    //Start gameloop
    while(!theGame.Exit)
    {
        //Beschrijf kamer
        theGame.DescribeLocation();
        //Toon acties
        theGame.ToonActies();
        //Lees actie uit
        theGame.VerwerkActie();
 
    }
}

Een bool property Exit binnen het GameManager object zal ons toelaten om de loop te stoppen wanneer het spel wordt beëindigd.

GameObject

Doorheen de verschillende locaties zullen elementen te vinden zijn. We beschrijven deze als GameObjects:

Location

De gebruiker kan van locatie naar locatie gaan. Een locatie bestaat uit een aantal zaken:

  • Een beschrijving en titel

  • Een lijst van GameObjecten (items) die zich op deze locatie bevinden

  • Een lijst van Exits, namelijk de richtingen waar de gebruiker naar toe kan gaan die aansluiten op een andere locatie

  • Een eerste versie van onze locatie klasse is dan:

Merk op dat we gebruik maken van List<> ipv arrays.

Exit

Iedere exit in een locatie definieert minstens 2 zaken:

  • De richting waar deze uitgang zich bevindt (Noord, Oost,Zuid, West)

  • Een referentie naar het locatie-object waar deze uitgang toegang tot verschaft

We krijgen dus al:

Waarbij Directions een eigen gemaakt enum-type is:

Van locatie veranderen

Binnen de locatie klasse voegen we een methode toe die de GameManager kan gebruiken om te weten te komen naar welke locatie de gebruiker gaat. De methode aanvaardt een Direction (i.e. de richting waarin de gebruiker wenst te gaan) en zal een referentie naar het location-object teruggeven waarnaar de gebruiker zal bewegen. Indien de richting waarin hij wenst te bewegen niet geldig is dan tonen we dit op het scherm:

Wanneer dus een exit wordt gevonden in de Exits lijst die voldoet aan de meegegeven Direction dan geven we een referentie terug naar de bijhorende locatie (GoesToLocation). Wordt er geen exit gevonden en bereiken we dus het einde van de foreach lus dan verschijnt de tekst op het scherm en geven we een referentie terug naar de huidige locatie.

GameObjects als vereisten om exit te gebruiken

Stel nu dat we soms willen dat een bepaalde locatie pas bereikt kan worden indien de gebruiker reeds een bepaald GameObject in zijn bezit heeft. Hiervoor moeten we 2 zaken aanpassen:

  • We beschrijven in de Exit klasse welk object(en) nodig zijn om deze exit te mogen gebruiken

  • We controleren of de speler het GameObject heeft wanneer deze naar een nieuwe locatie wil gaan mbv de GetLocationOnMove() methode.

De nieuwe, volledige Exit klasse wordt dan:

In deze ietwat knullige code tellen we dus of de speler alle GameObjecten in z’n inventory heeft (playerInventory) nodig om deze exit te gebruiken.

Deze methode TestPassCondition gebruiken we nu in de GetLocationOnMove()-methode in de Location klasse om te bepalen of de exit mag gebruikt worden. De methode wordt dan:

GameManager

Rest ons nu enkel nog de GameManager klasse te maken. Ruw gezien is deze als volgt:

Wat ogenblikkelijk opvalt zijn:

  • De 3 publieke methoden DescribeLocation,VerwerkActie en ToonActies

  • Een instantievariabelen currentLocation die een referentie bijhoudt naar de huidige locatie van de speler

  • 3 lijsten met daarin de objecten die de speler heeft (playerInventory), alle objecten in het spel (Objects) en alle locaties in het spel (GameLocation)

  • Een InitGame() methode waarin we alle gameobjecten, exits en locaties zullen aanmaken bij aanvang van het spel

  • Een bool Exit zodat de externe gameloop weet wanneer het spel gedaan is

We zullen nu de afzonderlijke methoden invullen:

DescribeLocation()

VerwerkActie()

We laten de speler dus toe door n,o,w,z in te typen dat gecontroleerd wordt naar welke nieuwe locatie zal gegaan worden. We passen hierbij de currentLocation property van de GameManager aan naar de, al dan niet nieuwe, locatie.

ToonActies()

InitGame()

In deze methode definiëren nu de volledige spelinhoud. Wil je dus bijvoorbeeld dit spel uitbreiden met extra kamers en objecten, dan doe je dat in deze methode. Ter illustratie tonen we eerst hoe we 2 locaties aanmaken en deze aan elkaar hangen mbv de Exits (waarbij kamer één zich ten zuiden van kamer 2 bevindt)

Vergeet niet op het einde de 2 kamers toe te voegen aan de GameLocation lijst van de GameManager, alsook in te stellen wat de beginkamer is.

GameInit met GameObject als conditie om kamer in te kunnen

Stel dat we even later in een kamer een sleutel plaatsen die als conditie dient om een andere kamer te kunnen openen. We schrijven dan in de GameInit() methode:

Een volledige GameInit ter illustratie

We hebben nu de belangrijkste onderdelen geschreven. We tonen daarom een iets uitgebreider spel, demo zeg maar, waar in we alles gecombineerd in actie zien:

What’s missing? Veel!

Maar een eerste uitdaging zou kunnen zijn: hoe kunnen we de speler objecten van de grond laten oprapen en in de inventaris plaatsen? Dat raadsel laten we aan jou over over om op te lossen!

Last updated

Was this helpful?