C-RTS: Implementatie KDTree

Door Gamebuster op woensdag 5 april 2017 13:37 - Reacties (6)
Categorie: Hobby RTS, Views: 1.582

Weer een performance update voor mijn Hobby RTS, deze keer met een KDTree implementatie voor het zoeken van vijandelijke tankjes. De implementatie kan nog veel verbeterd worden, maar de performance impact is al zeer groot merkbaar.



Ik wil nog wat optimalisaties doorvoeren met de huidige KDTree implementatie en dan kijken of ik daadwerkelijk een game ervan kan maken, met interactie enzo. Ook wil ik langzamerhand gaan kijken of ik de game op Windows kan draaien en of de game zich dan hetzelfde gedraagt (ofwel, of identieke input resulteert tot identiek eindresultaat). Zo niet, dan moet ik wijzigingen doen in de game tot het resultaat van de game wel identiek is.

Als dat gedaan is, de inputs synchroniseren over het netwerk en je hebt een soort van multiplayer RTS. Dan kan ik er een echte game van maken en onderzoeken hoe ik de game leuk kan maken. Dat, tegelijkertijd met manieren zoeken om de game nog sneller te maken. Ik heb veel ideeen daarover, waaronder multithreading (makkelijk toe te passen) en scheiding framerate & tickrate waarbij de tickrate naar 10Hz kan.

C-RTS: Stress-test

Door Gamebuster op zaterdag 1 april 2017 23:45 - Reacties (1)
Categorie: Hobby RTS, Views: 1.584

Mijn ambitie van de game is om zo veel mogelijk tankjes te kunnen simuleren. Als we in 1997 in de 100en units moeten kunnen hebben in een RTS, dan moeten we in 2017 toch makkelijk richting de 10.000 op 60fps? 100.000 misschien? Dat is in ieder geval wel mijn ambitie.

Ik ben er nog lang niet, maar ik heb al wel enkele stappen gemaakt richting wat betere performance. Hieronder een video waarin ik een benchmark van de game laat zien: Met een vaste seed voor random zorg ik ervoor dat iedere game 100% identiek is. Ik plaats 64 factories en laat ze lekker tankjes bouwen. De simulatie is niet synchroon gezet met de klok dus loopt zo snel mogelijk.

In de video zie je 3 benchmarks en een demo. Vlugge copy/paste uit mijn video-omschrijving:

0:00 Benchmark with old code (before grid, slow, 77.6 CPU-seconds)
1:30 Benchmark with newer code (after grid, faster, 26.3 CPU-seconds)
2:20 Benchmark with latest code (after scalable grid, faster, 16.1 CPU-seconds)
3:58 Start of long run of the demo. Whats how blue dominates the whole game

De video is met >1080p opgenomen. Youtube laat dit echter nog niet zien. Ik verwacht dat dit beter wordt, anders upload ik de raw video ergens.

C-RTS: Tankjes uit de fabriek maken plaats

Door Gamebuster op zondag 26 maart 2017 23:38 - Reacties (5)
Categorie: Hobby RTS, Views: 2.728



Tijdens de ontwikkeling van mijn poging tot een RTS in C had ik zojuist het concept van fabrieken af. Omdat tanks de neiging hadden om allemaal op dezelfde positie te gaan staan en ik (nog?) geen collision-detectie heb, had ik een snelle hack gemaakt waarbij tanks proberen van elkaar weg te rijden zodra ze dicht bij elkaar staan (wanneer ze minder dan 32 afstands-eenheden bij elkaar staan; ze zijn tevens 32 lang).

Dit heeft als zeer coole bijwerking dat tankjes netjes ruimte voor elkaar maken zodra ze uit de fabriek rollen, zoals te zien in bovenstaande video.

Hieronder een oudere video, waarin de tankjes op elkaar schieten:

Mechanics hobby RTS + start C++ implementatie

Door Gamebuster op maandag 13 april 2015 19:09 - Reacties (6)
Categorie: Hobby RTS, Views: 2.938

C++ coders, code review is welkom:
https://github.com/tobyhinloopen/My-CPP-RTS



De Hobby RTS waar ik al enkele artikeltjes over heb geschreven is nog steeds hard in ontwikkeling.

Om te beginnen, de RTS heeft o.a. energie en massa als resources. Er is geen globale opslag van resources. Energie kan draadloos gedeeld worden, moet gegenereerd worden met Massa of moet opgevangen worden met zonnecellen. Massa moet fysiek opgenomen, opgehaald, gedeeld of overgebracht worden.

Ik werk nu de mechanics uit. De "droom" van de game is groot, 1 significant deel van de "droom" is de mogelijkheid om je eigen units te ontwerpen. Hierbij bepaalt de uitrusting - de geselecteerde componenten - van de unit de eigenschappen van de unit.

Een unit begint volledig niet-bestaand. Er is geen "basis-unit" of frame; je begint met niets. Iedere feature die een unit kan hebben, moet je zelf toevoegen. Stel, we willen een simpel gevechtsvliegtuig maken.

Je gevechtsvliegtuig begin je dan bijv. met het geven van een frame. Dit frame is puur visueel en heeft geen invloed op de eigenschappen van de unit.

Voor een gevechtsvliegtuig heb je uiteraard wapens nodig. Als speler beschik je uit een set componenten, waaronder enkele wapens. We geven het vliegtuigje 2 laserwapens.

De toegevoegde laserwapens hebben stroom nodig om te schieten. Voor de stroom voegen we een power generator toe; deze zet een zeer kleine hoeveelheid mass om in stroom. De mass die nodig is om omgezet te worden wordt opgeslagen in een mass storage, die ook toegevoegd wordt aan de unit.

Onze unit kan nu schieten, mits er Mass opgeslagen is in de MassStorage.

De unit kan zich echter nog niet verplaatsen. Hiervoor voegen we een kleine verbrandingsmotor toe. Deze verbrandingsmotor verbruikt massa en zet deze om in beweging. De massa is afkomstig van de mass storage die we eerder al hebben toegevoegd. Uiteraard moet er wel massa aanwezig zijn in de storage; de MassStorage kan dus opraken, waarna de unit zonder wapens of motor zit. Bij het maken van de unit kan de mass storage ook meteen gevuld worden, maar dit is niet vereist (instelbaar)

Tot slot voegen we armor toe aan de unit. Per eenheid "armor" neemt de armor-eigenschap toe van de unit, waardoor de andere onderdelen beschermd zijn tegen damage. Hoe het toevoegen van armor visueel eruit zal zien, weet ik nog niet. Wel weet ik al dat de visuele indeling van units geen impact hebben op de eigenschappen van de unit. De indeling is puur visueel. De unit eigenschappen worden gebaseerd op puur de aanwezigheid van componenten, niet de positionering ervan.

Onze unit bestaat nu uit:

20x Armor
MassStorage (kleine opslag voor massa)
PowerGenerator (zet zeer kleine hoeveelheden massa om in energie)
LaserWeapon (x2, verbruikt energie per schot)
CombustionEngine (verbruikt mass)

Alle onderdelen die toegevoegd zijn hebben o.a. de volgende basis eigenschappen:

Shield
Wanneer een component een shield heeft, voegt deze shield-armor toe aan de unit. Shield beschermt de componenten tegen inkomende schade en kan kosteloos herladen worden. Verbruikt energie om online te houden en kan tegen extra energieverbruik zich herstellen tot maximale capaciteit na schade.

Armor
Armor beschermt de componenten wanneer er geen shield (meer) is. Bij schade verliest de armor zijn massa tot deze 0 is en de armor geen bescherming meer biedt. Reparatie van armor is alleen mogelijk door weer massa toe te voegen met speciale componenten bedoelt voor reparatie of constructie.

Health
Wanneer shield en armor geen bescherming meer bieden, blijft de health van een component over. De health is vaak laag; de componenten met de minste health zullen het eerste uitschakelen of zelfs exploderen wanneer deze van nature instabiel zijn. Reparatie van componenten die beschadigd zijn kan alleen gedaan worden door constructie units en verbruikt meer energie dan de oorspronkelijke constructie van de componenten.

Volatility
Sommige onderdelen zijn van nature explosief, zoals accus, generatoren en motoren. Wanneer de onderdelen beschadigd raken, kunnen ze dus schade toebrengen aan andere onderdelen in de unit en/of omliggende units. Volatility kan misbruikt worden voor suicide units.

Complexiteit
Bepaalt hoeveel energie en beÔnvloed de hoeveelheid tijd er nodig is om de component te maken of te repareren.

Massa
Bepaalt het gewicht van de unit, wat nadelig werkt op de behendigheid en snelheid van de unit. De massa is ook nodig bij het maken van de unit. Voor een Mass Storage telt de opgeslagen massa mee met het gewicht van de unit.

Het verbruik en productie van resources per onderdeel is ook vastgelegd. Dit kan bijv. zijn:


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Laser, in gebruik, per stuk:
  power_consumption: 40

Power Generator, in gebruik
  mass_consumption: 0.1
  energy_production: 60
  mass_capacity: 10
  energy_capacity: 240

Mass Storage
  mass_capacity: 40

CombustionEngine, in gebruik (vol gas)
  mass_consumption: 0.1



In detail:

De bovengenoemde onderdelen kunnen in totaal dus 50 massa opslaan. De generator kan zelf 240 energie opslaan en per seconde 60 genereren. Zodra energie "verbruikt" wordt, wordt dit opgenomen uit die 240. Zolang de energie opslag niet vol is, blijft er energie geproduceerd worden. Een lege accu kan in 4 seconden gevuld worden.

Met de in totaal 50 massa die opgeslagen kan zijn in de unit, kan de accu bijgeladen worden met 60 per seconde voor 50/0.1=500 seconden. Er kan dus in totaal 60*500=30.000 energie gegenereerd worden met een volle massa opslag.

Met 30.000 energie kunnen kan 1 laser 750 seconden lang schieten. Omdat er maximaal 60 energie per seconde geproduceerd kan worden en er 80 energie per seconde verbruikt wordt bij het afvuren van beide lasers, is er 20 energie per seconde nodig uit de accu voor het in stand houden van het vuren van de lasers. Dit houdt in dat de 2 lasers maximaal 240/20=12 seconden op vol vermogen kunnen vuren. Daarna neemt de fire-rate af tot 60/80=75%.

De bovenstaande situatie gaat er echter van uit dat de unit zich nooit verplaatst. De verbrandingsmotor verbruikt ook massa. Wanneer de unit nooit schiet, kan de unit op vol vermogen vliegen voor 50/0.1=500 seconden.

Wanneer de opslag leeg is, moet deze bijgeladen worden. Dit kan bij units die beschikken over opgeslagen massa en een component die mass transfer mogelijk maakt. O.a. de fabrieks-unit waar de unit in gemaakt is, heeft de mogelijkheid om de unit weer "bij te vullen". Tevens kan de fabrieks-unit ook beschadigde armor en componenten repareren. Je kan je unit ook demonteren bij de fabrieks-unit om de massa in de unit componenten weer op te nemen.

De game zal veel draaien rondom het verzamelen en beheren van Massa. Energie is makkelijk te verkrijgen en te beheren. Massa is zeldzaam en "uitdagend" te beheren. Omdat je energie kan verkrijgen uit massa, zullen de meeste units een energy generator en een mass storage aan boord hebben.

Massa zal nooit verloren gaan in een game. Bij het maken van een unit gaat de massa uit de fabrieks-unit's mass storages naar de componenten van de nieuwe unit. Alle massa blijft in die unit tot deze gedemonteerd wordt. Zelfs wanneer een unit volledig vernietigd is, kan de massa herbruikt worden. In enkele situaties kan massa van de units af gaan, door verbranding of vernietiging van bepaalde componenten. In dit geval zal de "verloren" massa "opgenomen" worden door de wereld, klaar om opnieuw verzameld te worden.

2D RTS: Sterrenhemel

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

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