Hobby: simpele 2D RTS game maken in C

Door Gamebuster op donderdag 19 december 2013 12:44 - Reacties (10)
Categorie: Hobby RTS, Views: 4.043

Waarschuwing: Deze blogpost bevat veel tekst.

Ik ben op dit moment veel bezig in mijn vrije tijd met de ontwikkeling van een 2D RTS game.

Al sinds 2010 heb ik een bepaald idee in mijn hoofd en het was al die tijd al mijn droom geweest om die game uit te werken. Al die jaren heb ik projectjes gestart om mijn game uit te werken; allen zijn echter niet ver gekomen.

Oorspronkelijk wilde ik de game maken in Javascript met HTML5 canvas, maar mijn ideeen waren veruit te complex om in Javascript uit te werken. Ik ging me verder verdiepen naar andere omgevingen om mijn game in te maken. Flash, Javascript + Flash canvas, Lua met Love2D, Java + diverse 2D/3D game engines, Unity3D en vast nog wel meer. Alle frameworks en talen die ik geprobeerd had vond ik niet geschikt voor mijn game.

http://i.imgur.com/WFdcIFv.png

In al die omgevingen en talen had ik diverse prototypes gemaakt. Om het interessant te houden voor mezelf had ik per prototype de focus gelegd op iets nieuws. De ene focuste ik me op rendering, de ander op pathfinding, ga zo maar door. In de 3 jaar dat ik eraan heb gewerkt heb ik vele simpele prototypes gemaakt die allen samen een zeer basic game kunnen vormen. Ik was echter nog steeds niet tevreden met alle frameworks gecombineerd met de talen waarin ik ze het gebruikt.

Niet gerelateerd aan mijn game had ik me tussendoor ook verdiept in berekeningen uitvoeren op de videokaart met OpenCL. In combinatie met Java + LWJGL had ik wat simpele demo's geschreven in OpenCL voor mezelf. Het begon met wat simpele berekeningen en later maakte ik een demo waarbij ik OpenCL gebruikte om naar vertex buffers te schrijven en te renderen met OpenGL.

Mijn game knaagde nog steeds aan me. Ik besloot mijn game te maken in C + OpenGL + OpenCL. Geen grote frameworks, geen IDE's, geen tutorials, gewoon alleen C + OpenGL + OpenCL.

Ik heb me vaker verdiept in C, OpenGL en OpenCL. Ik heb ze echter nooit allemaal in 1 project tegelijk gebruikt. OpenGL en OpenCL kan ik iets werkend mee maken. Ik ben er verre van een expert in, maar ik probeer altijd uit te zoeken wat iedere functie doet en wat de beste manier is om deze te gebruiken. Verder probeer ik altijd de code zodanig te schrijven dat er ruimte is voor optimalisatie. (proberen kan altijd he)

C is echter een ander verhaal. De basis syntax is niet zo spannend, maar er zitten een hoop dingen in C die je niet terugziet in andere talen die ik ken. Ik heb meerdere pogingen gedaan om C te snappen, maar echt begrijpen deed ik het nooit. Ik kon er *iets* in schrijven, ik had geen moeite met de syntax, maar de functie van header-files waren mij een raadsel en zelf compilen was pure magie voor mij.

Dit veranderde toen ik simpelweg 3 dingen ging doen:
- Mijn IDE wegflikkeren en Makefile tutorial opzoeken.
- "Learn C The Hard Way".
- C11 specificatie lezen. Ja echt, ik heb een groot deel van de C11 specificatie vlugjes doorgelezen. D.w.z. dat ik niet woord voor woord heb gelezen maar wel globaal dingen heb opgepikt.

Al gauw leerde ik waarom header files nuttig zijn, de basics van compilen en wat ongeveer de gedachten rondom pointers is.

Met deze kennis ging ik ambitieus aan de slag met mijn game in C, OpenGL en SDL voor crossplatform window/input management. Ik begin mijn project zo simpel mogelijk. Ik bepaal een stap die ik wil behalen, schrijf de stap zo simpel mogelijk uit, maak het werkend, debug het om te kijken of alles goed draait, dump het in GIT en bepaal de volgende stap.

Per stap schrijf ik pseudocode uit. Ik omschrijf wat er moet gebeuren, maak er een functienaam van en bepaal vervolgens in pseudocode wat er in die functie moet gebeuren. Dit blijf ik recursief toepassen tot de functie dusdanig simpel is dat ik 'm direct kan uitschrijven.

Wanneer de code werkt pak ik een debugger erbij, ga ik de code een klein beetje optimaliseren zonder de leesbaarheid veel te verminderen. Ik ga alle code nog eens na of alles een beetje doet wat ik wil. Als alles goed lijkt te werken ga ik verder met de volgende stap.

Dit heb ik nu enkele keren gedaan. Mijn stappen waren:
- Maak een basis project met een game-loop die enkel een venstertje toont.
- Teken enkele vierkantjes in beeld die heen-en-weer gaan. Hiermee test ik de timers in de game-loop.
- Voeg textures to aan de vierkantjes.
- Stap af van OpenGL direct mode naar VBO's.
- Handel basic input af, reageer op "sluiten" en laat pijltoetsen de "view" verplaatsen. (panning)

Deze stappen zijn allemaal uitstekend verlopen. Ik heb nu een venster met 100.000 bewegende sprites vloeiend draaiend en kan rondkijken met pijltoetjes.

De volgende stap is het toevoegen van wat logica. Ik ben teruggestapt naar 4 "sprites". Iedere sprite stelt een unit voor. Het doel van deze units is elkaar vernietigen. Dit heb ik verdeeld in 2 stappen:
- Maak logica waarbij de units kunnen bepalen op welke ze moeten schieten, hoe ze daarheen moeten vliegen en wanneer ze in bereik zijn om te schieten.
- Laat de units daadwerkelijk schieten. Dit zorgt voor het eerst voor een variabel aantal sprites in mijn code en is daarom een aparte stap. In het ontwerp van mijn code ben ik uitgegaan van een variabel aantal "entities", maar in praktijk is het aantal nog altijd "vast" gebleven.

De 1e stap hiervoor is bijna compleet: De units lijken wat te doen en zoeken elkaar daadwerkelijk op. De code hiervoor kon ik vrijwel 1-op-1 uit een oud prototype van mij overnemen. Toen ik de code draaide kwam ik erachter dat er iets niet helemaal goed ging: alle vliegtuigjes vlogen zijwaards, namen verre van optimale paden naar hun vijand toe of vlogen in eindeloze cirkels. Waarom wist ik niet, omdat de code wel werkt in mijn prototype.

Na wat testen kwam ik erachter: omdat ik telkens code baseer uit oudere prototypes, werkt de code niet goed samen. In het ene prototype was 0,0 de linker bovenhoek van het scherm, in de ander was het de linker onderhoek. Ik heb daarom besloten 1 standaard aan te houden en alle code gerelateerd aan hoekberekeningen en de coordinaten van units langs te gaan om te kijken of die zich goed houdt aan de standaard.

In deze blog zal ik regelmatig updates plaatsen van mijn game. Ik heb veel projecten gestart en niet afgemaakt, maar omdat ik al 3 jaar met deze bezig ben, heb ik blijkbaar een passie voor dit project. Wie weet blijft die passie en maak ik het deze keer wel af. Het zit al maanden lang vrijwel dagelijks in mijn hoofd.

Het uiteindelijke plan is een 2D RTS game waarbij snelle actie en grote hoeveelheden units mijn primaire doel is. Ik probeer dan ook zoveel mogelijk logica zodanig te ontwerpen dat het te parallelliseren is in OpenCL. Ik hoop op die manier tot in de 10.000 units in beeld te kunnen tonen en in de 100.000 units in-game te hebben.

Multiplayer ga ik me nog niet aan wagen, maar ik hoop dat wel ooit werkend te krijgen.