De volgende blog post, tenzij anders vermeld, is geschreven door een lid van Gamasutras community.
De geuite gedachten en meningen zijn die van de schrijver en niet die van Gamasutra of haar moederbedrijf.
Deel 1 – Messaging
Deel 2 – Memory
Deel 3 – Data & Cache
Deel 4 – Graphics Libraries
We leven in een geweldige tijd om ontwikkelaar te zijn. Met zo’n grote hoeveelheid geweldige AAA-grade engines beschikbaar voor iedereen, kan het maken van eenvoudige spellen zo eenvoudig zijn als drag-and-drop. Er lijkt tegenwoordig geen enkele reden meer te zijn om een engine te schrijven. En met het algemene sentiment, “Schrijf spellen, geen engines”, waarom zou je?
Dit artikel is vooral gericht op solo-ontwikkelaars en kleine teams. Ik ga uit van enige bekendheid met Object-georiënteerd programmeren.
Ik wil u enig inzicht geven in de aanpak van Engine-ontwikkeling en zal een eenvoudige fictieve Engine gebruiken om dit te illustreren.
Waarom een Engine schrijven?
Het korte antwoord is: Niet doen, als je het kunt vermijden.
Het leven is te kort om voor elk spel een engine te schrijven (Uit het boek 3D Graphics Programming van Sergei Savchenko)
De huidige selectie van uitstekende Engines zoals Unity, Unreal of CryEngine zijn zo flexibel als men maar kan hopen en kunnen gebruikt worden om zo’n beetje elk spel te maken. Voor meer gespecialiseerde taken zijn er natuurlijk meer gespecialiseerde oplossingen zoals Adventure Game Studio of RPG Maker, om er maar een paar te noemen. Zelfs de kosten van commerciële Engines zijn geen argument meer.
Er zijn nog maar een paar niche-redenen over om je eigen engine te schrijven:
- Je wilt leren hoe een engine werkt
- Je hebt bepaalde functionaliteiten nodig die niet beschikbaar zijn of de beschikbare oplossingen zijn instabiel
- Je gelooft dat je het beter / sneller kunt
- Je wilt controle houden over de ontwikkeling
Al deze redenen zijn volkomen geldig en als je dit leest, behoor je waarschijnlijk tot een van deze kampen. Het is niet mijn bedoeling om hier een lang “Welke engine moet ik gebruiken?” of “Moet ik een engine schrijven?” debat te voeren en ik zal er meteen induiken. Dus, laten we beginnen.
Hoe het schrijven van een Engine te mislukken
Wacht. Eerst zeg ik dat je er geen moet schrijven, en dan leg ik uit hoe je moet falen? Geweldige inleiding…
Hoe dan ook, er zijn veel dingen om te overwegen voordat je ook maar een regel code schrijft. Het eerste en grootste probleem van iedereen die een game engine begint te schrijven kan als volgt worden samengevat:
Ik wil zo snel mogelijk gameplay zien!
Hoe sneller je je realiseert dat het veel tijd zal kosten voordat je daadwerkelijk iets interessants ziet gebeuren, des te beter zal het je afgaan bij het schrijven van je engine.
Je code dwingen om zo snel mogelijk een of andere vorm van graphics of gameplay te laten zien, alleen maar om een visuele bevestiging van “voortgang” te hebben, is je grootste vijand op dit punt. Neem. Je. Tijd!
Denk er niet eens aan om met de graphics te beginnen. Je hebt waarschijnlijk al veel OpenGL / DirectX tutorials en boeken gelezen en weet hoe je een simpele driehoek of sprite moet renderen. Je zou kunnen denken dat een korte code snippet van het renderen van een kleine mesh op het scherm een goede plaats is om te beginnen. Dat is het niet.
Ja, je eerste vooruitgang zal verbazingwekkend zijn. Heck, je zou kunnen lopen rond een klein level in First-Person in slechts een dag kopiëren-plakken code snippets van verschillende tutorials en Stack Overflow. Maar ik garandeer je, dat je 2 dagen later elke regel van die code zult wissen. Nog erger, je zou zelfs ontmoedigd kunnen raken van het schrijven van een Engine, want het is niet motiverend om steeds minder te zien.
Het tweede grote probleem waar ontwikkelaars tegenaan lopen bij het schrijven van Engines is feature creep. Iedereen zou graag de heilige graal van de Engines schrijven. Iedereen wil die perfecte engine die alles kan. First Person Shooters, Tactische RPGs, noem maar op. Maar het simpele feit blijft, dat we dat niet kunnen. Nog niet. Kijk maar naar de grote namen. Zelfs Unity kan niet elk spelgenre perfect aan.
Neem het niet in je hoofd om een Engine te schrijven die meer dan één genre aankan in je eerste keer. Niet doen!
Waar te beginnen eigenlijk bij het schrijven van een Engine
Het schrijven van een Engine is als het engineeren van een echte Engine voor een auto. De stappen zijn eigenlijk vrij duidelijk, ervan uitgaande dat je weet aan welk spel (of auto) je werkt. Hier zijn ze:
- Stel precies vast wat je motor moet kunnen EN wat je motor niet moet kunnen.
- Organiseer de behoeften in Systems die je motor nodig zal hebben.
- Ontwerp je perfecte Architectuur die al deze Systems samenbindt.
- Herhaal de stappen 1. – 3. zo vaak mogelijk.
- Codeer.
Als (= als en alleen als) je genoeg tijd en moeite steekt in de stappen 1. – 4. en het Game Design niet plotseling verandert van een Horror Game in een Slot Machine (lees: Silent Hill), dan zal coderen een zeer plezierige onderneming zijn. Coderen zal nog steeds verre van gemakkelijk zijn, maar perfect beheersbaar, zelfs voor solo-ontwikkelaars.
Dit is de reden waarom dit artikel voornamelijk gaat over de stappen 1. – 4. Zie stap 5. als “Het invullen van de lege plekken. 50.000 LOC aan lege plekken”.
Het meest cruciale deel van dit alles is Stap 3. We zullen ons hier het meest op richten!
Stap 1. Bepaal de behoeften en de niet-behoeftigen
Al deze stappen lijken op het eerste gezicht nogal triviaal. Maar dat zijn ze niet. Je zou kunnen denken dat stap 1 van het ontwikkelingsproces van een First Person Shooter Engine als volgt kan worden samengevat:
Ik moet een level laden, het wapen van de speler, wat vijanden met AI. Klaar, op naar stap 2.
Was het maar zo makkelijk. De beste manier om stap 1 te doen is het hele spel te doorlopen, klik voor klik, actie voor actie, vanaf het klikken op de Icon op je Bureaublad, tot het drukken op de Exit toets na het rollen van de credits. Maak een lijst, een grote lijst van wat je nodig hebt. Maak een lijst van wat je zeker niet nodig hebt.
Dit zal waarschijnlijk als volgt gaan:
Ik start het spel en het gaat direct naar het Hoofdmenu. Zal het menu een statisch beeld gebruiken? Een Cut Scene? Hoe bedien ik het hoofdmenu, met de muis? Toetsenbord? Wat voor GUI elementen heb ik nodig voor het Hoofd Menu? Knoppen, Formulieren, Scrollbars? Hoe zit het met muziek?
En dat zijn alleen nog maar macro-overwegingen. Ga er zo gedetailleerd mogelijk op in. Besluiten dat je knoppen nodig hebt is prima, maar bedenk ook wat een knop kan doen.
Ik wil dat de knoppen 4 toestanden hebben, Omhoog, Hover, Omlaag, Uitgeschakeld. Heb ik geluid nodig voor de knoppen? Hoe zit het met speciale effecten? Worden ze geanimeerd in de ruststand?
Als je lijst met behoeften en behoeften aan het eind van het hoofdmenu nog maar 10 items bevat, heb je iets verkeerd gedaan.
In dit stadium simuleer je de motor in je brein en schrijf je op wat er moet gebeuren. Stap 1 zal bij elke herhaling duidelijker worden, maak u geen zorgen dat u de eerste keer iets over het hoofd ziet.
Stap 2. Organiseer de behoeften in systemen
Dus, u hebt uw lijsten van dingen die u nodig hebt en die u niet nodig hebt. Het is tijd om ze te organiseren. Het is duidelijk dat GUI gerelateerde dingen zoals knoppen in een soort GUI Systeem gaan. Rendering gerelateerde dingen gaan in het Graphics System / Engine.
Opnieuw, net als bij stap 1, beslissen over wat waar moet komen zal duidelijker zijn bij je tweede iteratie, na stap 3. Voor de eerste pass, groepeer ze logisch zoals in het voorbeeld hierboven.
De beste referentie over “wat gaat waar” en “wat doet wat” is zonder twijfel het boek Game Engine Architectuur door Jason Gregory.
Start met het groeperen van de functionaliteit. Begin manieren te bedenken om ze te combineren. Je hebt Camera->rotateYaw(float yaw)
en Camera->rotatePitch(float pitch)
niet nodig als je ze kunt combineren in Camera->rotate(float yaw, float pitch)
. Hou het simpel. Te veel functionaliteit (onthoud, feature creep) zal je later pijn doen.
Bedenk welke functionaliteit publiekelijk zichtbaar moet zijn en welke functionaliteit alleen in het systeem zelf hoeft te zitten. Bijvoorbeeld, je Renderer moet alle transparante Sprites sorteren voor het tekenen. De functie om deze sprites te sorteren hoeft echter niet openbaar te worden gemaakt. Je weet dat je transparante Sprites moet sorteren voor het tekenen, je hebt geen extern Systeem nodig om je dit te vertellen.
Stap 3. De Architectuur (Of, het eigenlijke Artikel)
We hadden het Artikel net zo goed hier kunnen beginnen. Dit is het interessante en belangrijke deel.
Eén van de eenvoudigst mogelijke architecturen van uw motor is elk systeem in een klasse onder te brengen en de hoofdspellus hun subroutines te laten aanroepen. Het zou er ongeveer zo uit kunnen zien:
while(isRunning)
{
Input->readInput();
isRunning = GameLogic->doLogic();
Camera->update();
World->update();
GUI->update();
AI->update();
Audio->play();
Render->draw();
}
Leek op het eerste gezicht heel redelijk. Je hebt alle basisprincipes onder controle, Input -> processing Input -> Output.
En inderdaad, dit zal volstaan voor een eenvoudig spel. Maar het zal een pijn zijn om te onderhouden. De reden hiervoor zou duidelijk moeten zijn: Afhankelijkheden.
Elk Systeem moet op de een of andere manier met andere systemen communiceren. We hebben geen enkele manier om dat te doen in onze Game Loop hierboven. Daarom geeft het voorbeeld duidelijk aan, dat elk systeem een referentie moet hebben van de andere systemen om iets zinnigs te kunnen doen. Onze GUI en Game Logic moeten iets weten over onze Input. Onze Renderer moet iets weten over onze Game Logic om iets zinnigs te kunnen weergeven.
Dit leidt tot dit architectonische wonder:
Als het naar Spaghetti ruikt, is het Spaghetti. Zeker niet wat we willen. Ja, het is gemakkelijk en snel te coderen. Ja, we krijgen acceptabele resultaten. Maar onderhoudbaar, is het niet. Verander ergens een klein stukje code en het kan verwoestende effecten hebben op alle andere systemen zonder dat we het weten.
Daarnaast, zal er altijd code zijn waar veel systemen toegang toe moeten hebben. Zowel de GUI als de Renderer moeten Draw calls doen of op zijn minst toegang hebben tot een soort Interface om dit voor ons af te handelen. Ja, we zouden elk systeem de macht kunnen geven om OpenGL / DirectX functies direct aan te roepen, maar we zullen eindigen met veel redundanties.
We zouden dit kunnen oplossen door alle tekenfuncties te verzamelen in het Renderer Systeem en die aan te roepen vanuit het GUI systeem. Maar dan zal het render systeem specifieke functies hebben voor de GUI. Deze hebben geen plaats in de Renderer en is dus in strijd met stap 1 en 2. Beslissingen, Beslissingen.
Dus het eerste wat we moeten overwegen is om onze Engine in Lagen te verdelen.
Engine Lasagne
Lasagna is beter dan Spaghetti. Tenminste programmeertechnisch. Vasthoudend aan ons Renderer Voorbeeld, wat we willen is OpenGL / DirectX functies aanroepen zonder ze direct in het Systeem aan te roepen. Dit ruikt als een Wrapper. En voor het grootste deel is het dat ook. We verzamelen alle teken-functionaliteit in een andere Klasse. Deze klassen zijn nog eenvoudiger dan onze Systemen. Laten we deze nieuwe klassen het Framework noemen.
Het idee hierachter is om veel van de low level API calls weg te abstraheren en ze te vormen tot iets dat is toegesneden op ons spel. We willen niet de Vertex Buffer instellen, de Index Buffer instellen, de Textures instellen, dit inschakelen, dat uitschakelen alleen maar om een eenvoudige tekenopdracht in ons Renderer Systeem te doen. Laten we al dat lage niveau spul in ons Framework zetten. En ik noem dit deel van het Framework gewoon “Draw”. Waarom? Nou, alles wat het doet is alles klaarzetten om te tekenen en het dan tekenen. Het maakt niet uit wat het tekent, waar het tekent, waarom het tekent. Dat wordt overgelaten aan het Renderer System.
Dit lijkt misschien een vreemde zaak, we willen snelheid in onze engine, toch? Meer Abstractie Lagen = Minder Snelheid.
En je zou gelijk hebben, als het de 90’s waren. Maar we hebben de onderhoudbaarheid nodig en kunnen leven met het nauwelijks merkbare snelheidsverlies voor de meeste onderdelen.
Hoe moet ons Draw Framework dan worden ontworpen? Simpel gezegd, als onze eigen kleine API. SFML is hier een goed voorbeeld van.
Belangrijke dingen om in gedachten te houden:
- Houd het goed gedocumenteerd. Welke functies hebben we? Wanneer kunnen ze worden aangeroepen? Hoe worden ze aangeroepen?
- Houd het simpel. Eenvoudige functies als drawMesh(Mesh* oMesh) of loadShader(String sPath) zullen je op de lange termijn gelukkig maken.
- Houd het functioneel. Wees niet te specifiek. In plaats van
drawButtonSprite
, heb je eendrawSprite
functie en laat de Caller de rest afhandelen.
Wat winnen we ermee? Veel:
- We hoeven ons Framework maar een keer op te zetten en kunnen het gebruiken in elk systeem dat we nodig hebben (GUI, Renderer….)
- We kunnen gemakkelijk de onderliggende API’s veranderen als we dat willen, zonder elk systeem te herschrijven. Overschakelen van OpenGL naar DirectX? Geen probleem, gewoon de Framework Class herschrijven.
- Het houdt de code in onze systemen schoon en strak.
- Het hebben van een goed gedocumenteerde Interface betekent, dat één persoon aan het Framework kan werken, terwijl één persoon in de System Layer werkt.
We eindigen waarschijnlijk met iets als dit:
Mijn vuistregel voor wat er in het Framework komt is nogal simpel. Als ik een externe bibliotheek moet aanroepen (OpenGL, OpenAL, SFML…) of als ik datastructuren/algoritmen heb die elk systeem nodig heeft, dan moet ik dat in het Framework doen.
We hebben nu onze eerste laag Lasagna klaar. Maar we hebben nog steeds die grote bal Spaghetti erboven. Laten we dat als volgende aanpakken.
Messaging
Het Grote Probleem blijft echter. Onze systemen zijn nog steeds allemaal met elkaar verbonden. Dat willen we niet. Er zijn een veelheid van manieren om met dit probleem om te gaan. Gebeurtenissen, Berichten, Abstracte Klassen met Functie Aanwijzers (Hoe esoterisch)…
Laten we het houden op Berichten. Dit is een eenvoudig concept dat nog steeds erg populair is in GUI programmering. Het is ook zeer geschikt als een eenvoudig voorbeeld voor onze Engine.
Het werkt als een postdienst. Bedrijf A stuurt een bericht naar bedrijf B met het verzoek iets te doen. Deze bedrijven hebben geen fysieke verbinding nodig. Bedrijf A gaat er gewoon van uit dat bedrijf B het op een gegeven moment zal doen. Maar op dit moment maakt het bedrijf A niet uit wanneer of hoe bedrijf B het doet. Het moet gewoon gedaan worden. Bedrijf B zou zelfs kunnen besluiten het bericht om te leiden naar bedrijf C en D en hen het te laten afhandelen.
We kunnen nog een stap verder gaan, bedrijf A hoeft het niet eens naar een specifiek iemand te sturen. Bedrijf A plaatst de brief gewoon en iedereen die zich verantwoordelijk voelt, zal hem afhandelen. Zo kunnen bedrijf C en D het verzoek direct afhandelen.
Het is duidelijk dat de bedrijven gelijk zijn aan onze systemen. Laten we eens kijken naar een eenvoudig voorbeeld:
- Framework meldt Input System dat “A” is ingedrukt
- Input vertaalt dat toetsaanslag “A” “Open Inventory” betekent en stuurt een Bericht met “Open Inventory”
- GUI handelt het bericht af en opent het venster Inventaris
- Game Logic handelt het bericht af en pauzeert het spel
Input geeft er niet eens om wat er met zijn bericht wordt gedaan. GUI kan het niet schelen dat Game Logic hetzelfde bericht ook verwerkt. Als ze allemaal gekoppeld zouden zijn, zou Input een functie in het GUI Systeem moeten aanroepen en een functie in Game Logic. Maar dat is niet meer nodig. We hebben dit succesvol kunnen ontkoppelen met behulp van Messages.
Hoe ziet een Message er uit? Het zou op zijn minst een Type moeten hebben. Bijvoorbeeld, het openen van de inventaris zou een of ander enum genaamd OPEN_INVENTORY
kunnen zijn. Dit volstaat voor eenvoudige berichten als deze. Meer geavanceerde berichten die gegevens moeten bevatten, hebben een manier nodig om die gegevens op te slaan. Er zijn een groot aantal manieren om dit te bereiken. De eenvoudigste is het gebruik van een eenvoudige map structuur.
Maar hoe versturen we berichten? Via een berichtenbus natuurlijk!
Is het niet prachtig? Geen spaghetti meer, gewoon goede oude lasagne. Ik heb onze spellogica met opzet aan de andere kant van de berichtenbus gezet. Zoals je kan zien, heeft het geen verbinding met de Framework laag. Dit is belangrijk om de verleiding te vermijden om “gewoon die ene functie aan te roepen”. Geloof me, vroeg of laat zal je dat willen, maar het zou ons ontwerp breken. We hebben al genoeg systemen die met het Framework te maken hebben, dat hoeft niet in onze Game Logic.
De Message Bus is een eenvoudige Class met verwijzingen naar elk Systeem. Als hij een bericht in de wachtrij heeft, stuurt de Message Bus het naar elk Systeem via een eenvoudige handleMessage(Msg msg)
aanroep. In ruil daarvoor heeft elk systeem een verwijzing naar de berichtenbus om berichten te kunnen posten. Dit kan uiteraard intern worden opgeslagen of worden doorgegeven als een functie-argument.
Al onze Systemen moeten dus erven of van de volgende vorm zijn:
class System
{
public:
void handleMessage(Msg *msg);
{
switch(msg->type)
{
//// Example
//case Msg::OPEN_INVENTORY:
// break;
}
}
private:
MessageBus *msgBus;
//// Usage: msgBus->postMessage(msg);
}
(Ja, ja, ruwe Pointers…)
Opeens verandert onze Game Loop in het simpelweg laten rondsturen van Berichten door de Berichtenbus. We moeten nog steeds elk systeem periodiek bijwerken via een of andere update()
-aanroep. Maar de communicatie zal anders worden afgehandeld.
Hoewel, net als bij onze Frameworks, het gebruik van Berichten overhead creëert. Dit zal de motor een beetje vertragen, laten we onszelf niet voor de gek houden. Maar dat maakt ons niet uit! We willen een schoon en simpel ontwerp. Een schone en eenvoudige architectuur!
En het coolste deel? We krijgen geweldige dingen gratis!
De Console
Elk bericht is eigenlijk een functie-aanroep. En elk bericht wordt zowat overal naartoe gestuurd! Wat als we een systeem hebben dat simpelweg elk bericht afdrukt in een uitvoervenster? Wat als dit systeem ook berichten kan sturen die we in dat venster typen?
Ja, we hebben zojuist een Console gemaakt. En het kostte ons maar een paar regels code. Ik was verbijsterd toen ik dit voor het eerst in actie zag. Het is niet eens aan iets gebonden, het bestaat gewoon.
Een console is natuurlijk erg handig tijdens het ontwikkelen van het spel en we kunnen het er gewoon uithalen in Release, als we niet willen dat de Speler dat soort toegang heeft.
In-Game Cinematics, Replays & Debugging
Wat als we Berichten vervalsen? Wat als we een nieuw systeem maken dat berichten stuurt op een bepaalde tijd? Stel je voor dat het iets verstuurt als MOVE_CAMERA
, gevolgd door ROTATE_OBJECT
.
En voila, we hebben In-Game Cinematics.
Wat als we gewoon de Input Messages opnemen die tijdens het spel zijn verstuurd en ze opslaan in een bestand?
En voila, we hebben Replays.
Wat als we gewoon alles opnemen wat de speler doet, en als het spel crasht, ze die data bestanden naar ons laten sturen?
En voila, we hebben een exacte kopie van de spelers acties die tot de crash hebben geleid.
Multi-Threading
Multi-Threading? Ja, Multi-Threading. We hebben al onze systemen ontkoppeld. Dat betekent dat ze hun berichten kunnen verwerken wanneer ze maar willen, hoe ze maar willen en vooral, waar ze maar willen. We kunnen onze berichtenbus laten beslissen op welke draad elk systeem een bericht moet verwerken -> Multi-Threading
Frame Rate Fixing
We hebben te veel berichten om dit frame te verwerken? Geen probleem, we houden ze in de berichtenbus en sturen ze het volgende frame. Dit geeft ons de mogelijkheid om ervoor te zorgen dat ons spel op een soepele 60 FPS loopt. Gamers zullen niet merken dat de AI een paar frames langer doet om te “denken”. Ze zullen echter wel merken dat de Frame Rate daalt.
Boodschappen zijn cool.
Het is belangrijk dat we elk bericht en z’n parameters nauwkeurig documenteren. Behandel het als een API. Als je dit goed doet, kan iedere ontwikkelaar aan verschillende systemen werken zonder iets te breken. Zelfs als een Systeem offline is of in aanbouw, zal het Spel nog steeds draaien en kan het getest worden. Geen Audio Systeem? Dat is prima, we hebben nog steeds Visuals. Geen Renderer, dat is prima, we kunnen de Console gebruiken…
Maar Berichten zijn niet perfect. Helaas.
Soms willen we de uitkomst van een bericht weten. Soms willen we dat ze onmiddellijk worden verwerkt. We moeten uitvoerbare opties vinden. Een oplossing hiervoor is een Speedway. Behalve een eenvoudige postMessage
functie, kunnen we een postImmediateMessage
functie implementeren die onmiddellijk wordt verwerkt. Het afhandelen van retourberichten is veel eenvoudiger. Die worden vroeg of laat naar onze handleMessage
functie gestuurd. We hoeven dit alleen maar te onthouden wanneer we een bericht plaatsen.
Onmiddellijke berichten breken uiteraard Multi-Threading en Frame Rate Fixing als ze in overmaat worden gedaan. Het is dus van vitaal belang dat je je beperkt in het gebruik ervan.
Maar het grootste probleem met dit systeem is de latency. Het is niet de snelste Architectuur. Als je werkt aan een First Person Shooter met twitch-achtige reactietijden, kan dit een spelbreker zijn.
Terug naar het ontwerpen van onze architectuur
We hebben besloten om Systems en een Message Bus te gebruiken. We weten precies hoe we onze Engine willen structureren.
Het is tijd voor stap 4 van ons ontwerpproces. Iteratie. Sommige functies passen misschien niet in een systeem, daar moeten we een oplossing voor vinden. Sommige functies moeten uitvoerig worden aangeroepen en zouden de Message Bus verstoppen, we moeten een oplossing vinden.
Dit kost tijd. Maar het is de moeite waard op de lange termijn.
Het is eindelijk tijd om te coderen!
Stap 4. Waar te beginnen met coderen?
Voordat je begint met coderen, lees het boek/de artikelen Game Programming Patterns van Robert Nystrom.
Overigens heb ik een klein stappenplan geschetst dat je zou kunnen volgen. Het is verre van de beste manier, maar het is productief.
- Als je voor een Message Bus type Engine gaat, overweeg dan eerst de Console en de Message Bus te coderen. Als die eenmaal zijn geïmplementeerd, kunt u het bestaan van elk systeem dat nog niet is gecodeerd, faken. Je hebt constante controle over de hele engine in elke fase van de ontwikkeling.
- Neem als volgende de GUI in overweging, evenals de benodigde teken-functionaliteit binnen het Framework. Een solide GUI in combinatie met de Console zal je in staat stellen alle andere systemen nog eenvoudiger te vervalsen. Testen zal een fluitje van een cent zijn.
- Daarna komt het raamwerk, althans de interface. Functionaliteit kan later volgen.
- Daarna ga je verder met de andere systemen, inclusief Gameplay.
Je zult merken dat het renderen van Gameplay het laatste is wat je doet. En dat is maar goed ook! Het zal zoveel meer voldoening geven en je gemotiveerd houden om de laatste hand te leggen aan je Engine.
Je Game Designer zou je tijdens dit proces wel eens kunnen neerschieten. Gameplay testen via Console commando’s is ongeveer net zo leuk als Counter Strike spelen via IRC.
Conclusie
Neem je tijd om een solide Architectuur te vinden en blijf daarbij! Dat is het advies dat u hopelijk uit dit artikel meeneemt. Als u dit doet, zult u in staat zijn om aan het eind van de dag een prima en onderhoudbare Engine te bouwen. Of eeuw.
Persoonlijk geniet ik meer van het schrijven van Engines dan van al dat Gameplay gedoe. Als je vragen hebt, voel je vrij om contact met me op te nemen via Twitter @Spellwrath. Ik ben momenteel een andere Engine aan het afmaken met de methoden die ik in dit artikel heb beschreven.
Deel 2 vind je hier.