EotB – Grafikmotorn

Det är dags att bygga ihop en grafikmotor som kan rendera all trevlig grafik som vi lyckats plocka fram ur Eye of the Beholder. Detta är redan den 6:e delen i en serie som handlar lite om retro gaming och hur spel konstruerades förr.

MonoEye

Det kommer nog inte som en överraskning men vi kommer att använda MonoGame. Vi skapar först ett nytt projekt som vi döpte till ”MonoEye” av typen ”MonoGame Windows Projekt”. Tanken med detta projekt är att det ska bli Open Source och landa på GitHub när vi kommit lite längre fram. Tills vidare kommer källkoden att kunna laddas ned som innan i artiklarna.

Vi står inför följande uppgifter:

  • Lägga till alla klasser från ”PakExtract”.
  • Rendera grafiken till MonoGame Texture2D.
  • Lägga till lite testdata för banan.
  • Rendera väggarna.

Hjälpklasser

Vi kommer att använda ett tvådimensionellt fält för att hålla koll på väggarna i banan. Eftersom vi kommer att behöva indexera med heltal och kunna beräkna saker som ”två steg fram och ett åt vänster”, oavsett riktning på kartan, så har vi nytta av en klass Vector2Int som fungerar ungefär som Vector2 men som då endast använder heltal.

Vi överlagrar en del operatorer. På så vis kan vi räkna och t.ex. lägga ihop en position med en riktning. Rent tekniskt är klassen ingen klass utan en struct. Man pratar om värdetyp istället för referenstyp, vi diskuterar ämnet lite i artikeln OOP – Polymorfism.

Med metoderna Rotate90DegreesRight och Rotate90DegreesLeft har vi enkel rotation på riktningen. Vi kommer att använda klassen för att beskriva positioner i banan samt riktningar.

En annan finess med klassen är att den är ”immutable”. Kort beskrivet betyder det att du inte kan ändra värden/innehåll på en Vector2Int utan att samtidigt skapa en ny Vector2Int. Studera koden ovan och se om du kan se vad vi menar.

En annan liten hjälpmetod som vi kommer ha nytta av är Index. Denna skapar vi som en ”extension method” för alla variabler av typen int[,]. Denna metod kommer att snabbt ge oss värdet i ett 2D fält bara genom att skicka en en Vector2Int.

Mer data

Tidigare har vi i klassen WallRenderData lagt in en massa data som hjälper oss att rendera väggarna. Denna data kompletterar vi med vilken position på kartan som hänger ihop med vilken väggtyp. Positionerna som vi tidigare benämnt A-Q kommer nu att få informationen StepsForward och StepsLeft för att enkelt kunna avgöra, i förhållande till positionen på banan, vilket index som gäller för väggdata.

T.ex. ”N-south” ligger ett steg fram. Positionen ”G-south” ligger 3 steg fram och -3 steg till vänster (alltså 3 till höger), o.s.v. Ladda ned källkoden och kolla, vi listar inte denna fil en gång till just nu.

Till vår tänkta banan så definierar vi olika väggtyper.

Dessa typer stämmer väl in med de väggtyper vi redan identifierat i BRICK.VMP. Alltså två olika ”vanliga” väggtyper och dörrar som nummer 3.

Vår tanke är sedan att generera en Texture2D för varje väggtyp som hör till varje position. Alltså vi har alla positioner A-Q, framifrån och sidledes,  totalt 25 st, alla definierade i WallRenderData. Vi skapar en ny klass som representerar en position i ”fönstret till världen”. Vi behöver då veta position i förhållande till spelarens position på banan, position för uppritning i fönstret samt alla varianter av grafik beroende på vilken väggtyp som ska visas.

Anpassningar MonoGame

Istället för att rendera grafik till Bitmap så måste vi rendera till Texture2D. Dessa förändringar är inte så tekniskt intressanta så vi nöjer oss med att konstatera att dessa behöver göras.

Grafikmotorn

När vi nu har alla klasser, data och hjälpklasser på plats så blir grafikmotorn rätt kompakt och lättläslig.

Definitionen av banan är väldigt simpel just nu (rad #22).

Renderingen till Texture2D sker på rad #57-75. Vi anropar med negativa offset för att börja rita alla texturer på position (0,0).

Vi laddar också grafiken till UI:t för att öka Eye of the Beholder-känslan i demot.

I Update() läser vi bara av tangentbordet och kollar så att vi kan gå till nästa tänkta position. Se användningen av metoden Index på rad #117. Koden blir rätt snygg och lättläslig.

När vi sedan ska rita upp allt så behövs endast en loop som går igenom alla 25 positioner och ritar, vid behov, ut rätt textur! Mycket ren kod. Vi hoppar såklart över uppritning av typ 0 (=ingenting) och index som ligger utanför kartan. Nedan kan ses resultatet.

Avslutning

Tills vidare för ni nöja er med en stillbild. Inom kort kommer vi lägga upp ett litet Youtube-klipp. Ladda annars hem källkoden och tillhörande PAK-filer och testa lite själva!

I nästa artikel kommer vi att ladda den riktiga banan för level 1. Vi kommer också att försöka rendera alla dekorationer så som spakar, avlopp, dörrar, handtag, etc.

Scroll to top