2D RTS: Sterrenhemel

Door Gamebuster op zondag 22 december 2013 13:40 - Reacties (7)
Categorie: Hobby RTS, Views: 4.451

Als hobby maak ik een simpele 2D RTS in een "space-setting" in C+SDL+OpenGL+OpenCL. In deze blogposts omschrijf ik het ontwikkel proces en waar ik allemaal tegenaan loop. Zie ook de 1e blogpost (veel tekst)

Sinds mijn laatste blogpost ben ik vrij druk geweest met allerlei andere zaken, niet gerelateerd aan mijn RTS, dus ik ben nog niet veel verder gekomen. Als tussendoortje begon ik te denken over hoe ik exact de achterliggende sterrenhemel wilde implementeren.

Ik begon met het openen van photoshop om te kijken of ik een idee uitgewerkt kon krijgen, maar dit liep niet uit tot een bevredigend resultaat, simpelweg omdat ik totaal geen photoshop persoon ben.

Toch had ik wel een idee in mijn hoofd. Ik beeldde me sterrenhemel in met als basis stipjes die sterren voorstellen. De kleuren van deze stippen zouden variabel tussen oranje/rood, wit en lichtblauw zijn. Ik had die kleuren om voor mij nog onbekende rede in mijn hoofd: Waarom had ik in mijn hoofd dat mijn "stippen" moeten variŽren tussen die kleuren?

Ik ben gaan duckduckgoŽn en al gauw kwam ik op het princiepe van kleur-temperatuur. Dit ben ik wel eens vaker tegengekomen, zoals bij de aanschaf van lampen en bij het instellen van F.Lux. Het is me nooit echt doorgedrongen wat het precies inhield e.d.

Na wat naÔve logica in mijn hoofd zocht ik een formule op om RGB kleuren te genereren o.b.v. een kleurtemperatuur. Ik kwam een resultaat tegen met een pseudo-code formule en wat plaatjes van de resultaten:

http://i.imgur.com/4uvKcu8.png
Resulterende kleuren van de code met 1500K tot 15.000K als input. bron

Vlugjes maakte ik een paar HTML, CSS en JS bestandjes aan om in HTML5 canvas het algoritme uit te proberen. Een HTML5 canvas in een webpagina krijgen heb ik vele keren gedaan, dus dat kon ik direct uit mijn hoofd uittikken. Ik vulde de canvas met zwart en had mijn schildersdoek klaar liggen om een zooi stippen op te tekenen.

http://i.imgur.com/b9nEsPb.jpg

Ik werkte de formule uit en breidde de formule uit met wat functies om een random kleurtemperatuur te genereren.


JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function color_cap(c) {
  return Math.min(255, Math.max(0, c));
}

// Calculate RGB color for color temp. in Kelvin. Only supports range 1000 ~ 40'000.
function color_temperature_to_color_string(k) {
  var temperature = k / 100;
  var r = temperature <= 66 ? 255 : color_cap(329.698727446 * Math.pow(temperature - 60, - 0.1332047592));
  var g = color_cap(temperature <= 66 ? (99.4708025861 * Math.log(temperature) - 161.1195681661) : (288.1221695283 * Math.pow(temperature - 60, -0.0755148492)));
  var b = temperature >= 66 ? 255 : color_cap(138.5177312231 * Math.log(temperature - 10) - 305.0447927307);
  return "rgb("+r.toFixed()+","+g.toFixed()+","+b.toFixed()+")";
}

function random_color_temperature() {
  // 2000 ~ 2000*8
  return Math.pow(8, Math.random()) * 2000;
}

function random_star_color() {
  return color_temperature_to_color_string(random_color_temperature());
}



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

Dit gaf een klein beetje wat ik in gedachten had. Ik had mijn random kleurtjes en was wel aardig tevreden met de kleuren. De locatie van de sterren zelf vond ik echter erg saai. De "randomness" had geen leuke variatie erin zitten. Ik heb geen idee hoe sterren in het echt zich in de ruimte bevinden ten opzichte van elkaar en of een simpele Math.random()*width enigszins vergelijkbaar is met de realiteit. M.a.w., ik weet niet of sterren gewoon maar "ergens zitten" of dat ze voornamelijk in groepjes zijn.

De realiteit vind ik echter niet zo interessant, ik wilde gewoon meer variatie. Ik besloot daarom te kijken of ik de sterren wat meer naar elkaar toe kon trekken. Ik herschreef de code verantwoordelijk voor de coordinaten van de sterren en had daarbij besloten om te proberen in plaats van n sterren te genereren, om n/a groepen met sterren te genereren en in iedere groep a sterren te genereren met een random afstand vanaf het "centrum" van die groep.

Hier de code:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// The number of "star groups" to generate.
var number_of_groups = 300;

// The radius of the group of stars
var group_radius = 100;
var group_gravity = 2;

// The number of stars per group.
var stars_per_group = 20;

function render_star(x, y) {
  c2d.fillStyle = random_star_color();
  c2d.fillRect(x, y, 1, 1);
}

function render_group(x, y) {
  for(var i=0; i<stars_per_group; i++) {
    var distance = Math.pow(Math.random(), group_gravity) * group_radius;
    var angle = Math.random() * Math.PI * 2;
    var star_x = x - Math.sin(angle) * distance;
    var star_y = y + Math.cos(angle) * distance;

    // round here to prevent "blurred" stars
    render_star(Math.round(star_x), Math.round(star_y));
  }
}

function render_stars() {
  for(var i=0; i<number_of_groups; i++) {
    var x = Math.random() * width;
    var y = Math.random() * height;
    render_group(x, y);
  }
}



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

Hier kan ik mee leven. De coordinaten van de sterren spreken mij nu wel aardig aan. Ik vond het echter nog wel erg kaal rondom de sterren. Ik wilde een soort "lichtvlek" om iedere ster hebben, alsof je naar een lamp in de mist kijkt. Nogmaals, ik weet niet of het realistisch is, het leek mij gewoon een leuk visueel effect geven.

Ik was niet van plan om dat soort effecten in Javascript te gaan implementeren; dat zou me voor nu iets teveel gedoe zijn om alleen te kijken of het leuk zou staan. Ik maakte daarom een PNG dump van mijn canvas en opende deze in Photoshop.

Ik kopieerde mijn sterrenhemel als meerdere lagen en met wat spelen met Gaussian Blur, blending settings en opacity kwam ik met een resultaat die weer een stapje dichterbij komt met het beeld dat ik voor ogen heb.

http://i.imgur.com/7izEvgE.png

Tot slot wilde ik nog de achtergrond minder "zwart" maken. Dit deed ik door dezelfde sterrenhemel nog 3 keer te genereren en op dezelfde manier te bewerken. Vervolgens plakte ik de 3 afbeeldingen met 20%, 40% en 60% opacity over de bestaande sterrenhemel heen.

Het resultaat (te zien onder deze alinea) is verre van perfect, maar gezien ik het in een avondje heb kunnen maken ben ik wel tevreden ermee. Ik weet nu in ieder geval hoe ik in de toekomst de sterrenhemel in de achtergrond zou kunnen implementeren voor de RTS. In de daadwerkelijke code kan ik misschien nog heel subtiel parallelex scrolling toepassen om het een wat meer dynamisch gevoel te geven.

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

Hobby: simpele 2D RTS game maken in C

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

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.

A4 afrit Hoofddorp

Door Gamebuster op maandag 16 december 2013 10:11 - Reacties (22)
Categorie: quite useless, Views: 4.097

Mijn eerste reactie bij de nieuwe A4 / A5 afrit Hoofddorp / N201

http://i.imgur.com/kPWHQLV.gif