Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Game Development
  2. Programming
Gamedevelopment

Codering van een Custom Sequence Generator om een ​​Starscape te Renderen

by
Difficulty:IntermediateLength:LongLanguages:

Dutch (Nederlands) translation by Adjatay Bashroh Aldad (you can also view the original English article)

In mijn vorige artikel, legde ik het verschil uit tussen een pseudowillekeurige nummergenerator en een sequentiegenerator en onderzocht ik de voordelen die een sequentiegenerator heeft ten opzichte van een PRNG. In deze tutorial coderen we een vrij eenvoudige sequentiegenerator. Het genereert een reeks cijfers, manipuleert en interpreteert deze reeks, en gebruikt het vervolgens om een ​​heel eenvoudige sterrencape te tekenen.

Opmerking: hoewel deze tutorial met behulp van Java is geschreven, zou je in bijna elke game-ontwikkelomgeving dezelfde technieken en concepten moeten kunnen gebruiken.


Maken en initialiseren van de afbeelding

Het eerste dat we moeten doen is de afbeelding maken. Voor deze sequentiegenerator gaan we een 1000×1000px afbeelding maken om het genereren van nummers zo eenvoudig mogelijk te houden. Verschillende talen doen dit anders, dus gebruik de nodige code voor uw dev-platform.

Als je de afbeelding hebt gemaakt, is het tijd om hem een ​​achtergrondkleur te geven. Omdat we het hebben over een sterrenhemel, zou het verstandiger zijn om te beginnen met een zwarte achtergrond (#000000) en dan de witte sterren toe te voegen, in plaats van andersom.


Een Sterrenprofiel en Een Sterrenveld Maken

Voordat we aan de sequentiegenerator beginnen te werken, moet je erachter komen waar je mee wilt beginnen. Dit betekent weten wat je wilt maken en hoe verschillende zaden en nummers variëren wat je wilt creëren - in dit geval de sterren.

Om dit te doen, moeten we een voorbeeldsterprofiel maken dat klassevariabelen bevat die enkele eigenschappen van de sterren aangeven. Om het simpel te houden, beginnen we met slechts drie attributen:

  • x-coördinaat
  • y-coördinaat
  • grootte

Elk van de drie attributen heeft waarden van 0 tot 999, wat betekent dat aan elk attribuut drie cijfers zijn toegewezen. Dit alles wordt opgeslagen in een Star klasse.

Twee belangrijke methoden in de klasse Star zijn getSize() en getRadiusPx(). De methode getSize() retourneert de stergrootte, verkleind tot een decimaal getal tussen nul en één, en de methode getRadiusPx() retourneert hoe groot de straal van de ster in de uiteindelijke afbeelding moet zijn.

Ik heb gemerkt dat 4 pixels zorgt voor een goede maximale radius in mijn demo, dus getRadiusPx() zal gewoon de waarde van getSize() vermenigvuldigd met vier retourneren. Als de methode getSize() bijvoorbeeld een straal van 0,4 retourneert, geeft de methode getRadiusPx() een straal van 1,6px.

We moeten ook een heel eenvoudige klas maken wiens taak erin bestaat om alle sterren in elke reeks sterren bij te houden. De Starfield klasse bestaat alleen uit methoden die sterren uit een ArrayList toevoegen, verwijderen of ophalen. Het moet ook de ArrayList kunnen retourneren.


Planning van de Reeks Generator

Nu we het sterprofiel hebben voltooid en de afbeelding hebben geïnitialiseerd, weten we enkele belangrijke opmerkingen over de sequentiegenerator die we willen maken.

Ten eerste weten we dat de breedte en hoogte van de afbeelding 1000px is. Dit betekent dat, om de beschikbare bronnen te exploiteren, het bereik van x- en y-coördinaten moet vallen in het bereik 0-999. Aangezien twee van de vereiste getallen in hetzelfde bereik vallen, kunnen we hetzelfde bereik toepassen op de grootte van de ster om uniformiteit te behouden. De grootte zal later worden verkleind wanneer we de reeks getallen interpreteren.

We gaan een aantal klassenvariabelen gebruiken. Deze omvatten: s_seed, één geheel getal dat de hele reeks definieert; s_start en s_end, twee gehele getallen die worden gegenereerd door het zaad in tweeën te splitsen; en s_current, een geheel getal dat het meest recent gegenereerde nummer in de reeks bevat.

Creating a sequence
Zie deze afbeelding van mijn vorige artikel. 1234 is het zaad en 12 en 34 zijn de beginwaarden van s_start en s_end.
Tip: Merk op dat elk gegenereerd nummer afkomstig is van het zaad; er is geen oproep voor willekeurig(). Dit betekent dat hetzelfde zaad altijd hetzelfde sterrenbeeld zal genereren.

We zullen ook worden met behulp van s_sequence, een String die de algehele volgorde zal houden. De laatste twee klassenvariabelen zijn s_image (van het type Afbeelding - een klasse die we later zullen maken) en s_starfield (van het type Starfield, de klasse die we zojuist hebben gemaakt). De eerste slaat de afbeelding op, terwijl de tweede het starfield bevat.

De route die we gaan volgen om deze generator te maken is vrij eenvoudig. Eerst moeten we een constructeur maken die een zaadje accepteert. Wanneer dit is gebeurd, moeten we een methode maken die een geheel getal accepteert dat het aantal sterren vertegenwoordigt dat moet worden gemaakt. Deze methode zou dan de eigenlijke generator moeten bellen om met de cijfers te komen. En nu begint het echte werk ... het creëren van de sequentiegenerator.


Codering van de Sequentie Generator

Het eerste dat een sequentiegenerator hoeft te doen, is een zaad accepteren. Zoals gezegd, splitsen we het zaad in tweeën: de eerste twee cijfers en de laatste twee cijfers. Om deze reden moeten we controleren of het zaad vier cijfers heeft en pad met nullen als dit niet het geval is. Wanneer dit is gebeurd, kunnen we de seed-string in twee variabelen splitsen: s_start en s_end. (Merk op dat de zaadjes zelf geen deel uitmaken van de feitelijke volgorde.)

Dus:

  • seed = 1234 betekent s_start = 12 en s_end = 34
  • seed = 7 betekent s_start = 00 en s_end = 07
  • seed = 303 betekent s_start = 03 en s_end = 03

Next in line: maak een andere methode die, gegeven de twee nummers, het volgende nummer in de reeks genereert.

Het vinden van de juiste formule is een moe proces. Het betekent meestal urenlang proberen om een ​​reeks te vinden die niet te veel patronen in de resulterende afbeelding bevat. Daarom zou het verstandiger zijn om de beste formule te vinden zodra we het beeld daadwerkelijk kunnen zien, in plaats van nu. Waar we op dit moment in geïnteresseerd zijn, is het vinden van een formule die een reeks genereert die min of meer willekeurig is. Om deze reden zullen we dezelfde formule gebruiken die in de Fibonacci-reeks wordt gebruikt: toevoeging van de twee getallen.

Wanneer dit is gebeurd, kunnen we nu verder gaan en beginnen met het maken van de reeks. In een andere methode zullen we het initiële zaad manipuleren om een ​​hele stroom getallen te genereren, die vervolgens kunnen worden geïnterpreteerd als de attributen van het sterprofiel.

We weten dat voor een bepaalde ster we negen cijfers nodig hebben: de eerste drie definiëren de x-coördinaat, de middelste drie definiëren de y-coördinaat en de laatste drie bepalen de grootte. Daarom is het, net als bij het voeren van het zaad, belangrijk om uniformiteit te behouden om ervoor te zorgen dat elk gegenereerd getal uit drie cijfers bestaat. In dit geval moeten we het nummer ook inkorten als het groter is dan 999.

Dit is vrij gelijkaardig aan wat we eerder deden. We hoeven alleen het nummer op te slaan in een tijdelijke string, temp, en dan het eerste cijfer weg te gooien. Als het nummer geen drie cijfers heeft, moeten we het pad vullen met nullen zoals we eerder deden.

Met dat ingepakt, zouden we nu een andere methode moeten maken die een sterprofiel creëert en retourneert elke keer dat we drie getallen genereren. Met behulp van deze methode kunnen we de ster vervolgens toevoegen aan de ArrayList van sterren.


Putting It All Together

Nadat dit is voltooid, kunnen we de generator assembleren. Het zou het aantal sterren moeten accepteren dat het moet genereren.

We weten al dat we voor één ster, negen cijfers, moeten dus deze generator moet houden van de telling van het aantal tekens in de snaren. De teller, s_counter, slaat de maximale lengte van de reeks. Dus we vermenigvuldigen het aantal sterren door negen en verwijderen een aangezien een tekenreeks bij index nul begint.

We moeten ook houden van de telling van het aantal tekens, die hebben we nadat we laatst een ster zijn gegenereerd. Voor deze taak gaan we s_starcounter gebruiken. In een for lus, die herhalen zullen totdat de serie lengte gelijk is aan s_counter, kunnen we nu noemen de methoden die we tot nu toe hebt gemaakt.

Tip: we moeten niet vergeten s_start en s_end te vervangen, anders blijven we hetzelfde nummer steeds opnieuw genereren!

Sterren Tekenen

Nu het moeilijke gedeelte voorbij is, is het eindelijk tijd om over te gaan naar de klasse Image en sterren te gaan tekenen.

In een methode die een Starfield accepteert, maken we eerst een exemplaar van een Kleur en halen we vervolgens het aantal sterren op dat we moeten tekenen. In een for lus zullen we alle sterren tekenen. Na het maken van een kopie van de huidige ster, is het belangrijk dat we de straal van de ster worden opgehaald. Gezien het feit dat het aantal pixels een geheel getal is, moeten we toevoegen aan de straal om het een geheel getal.

Om de ster te tekenen, gebruiken we een radiaal verloop.

An example of a radial gradient
Een voorbeeld van een radiaal verloop

De dekking van een radiale gradient hangt af van de afstand van een pixel tot het midden. Het midden van de cirkel heeft coördinaten (0,0). Met behulp van de meest gebruikelijke conventie heeft elke pixel links van het midden een negatieve x-coördinaat en elke pixel hieronder heeft een negatieve y-coördinaat.

Daarom beginnen de geneste for lussen met een negatief getal. Met behulp van de stelling van Pythagoras berekenen we de afstand vanaf het middelpunt van de cirkel en gebruiken deze om de dekking op te halen. Voor sterren met de kleinst mogelijke straal (1px), hangt hun dekking alleen af ​​van hun grootte.

Om alles af te ronden, moeten we een methode maken die een String accepteert en deze gebruikt om de afbeelding met die bestandsnaam op te slaan. In de generator moeten we eerst de afbeelding maken. Dan zouden we deze laatste twee methoden uit de sequentiegenerator moeten noemen.

In de Hoofd klasse moeten we een instantie van de sequentiegenerator maken, een seed toewijzen en een goed aantal sterren krijgen (400 zou voldoende moeten zijn). Probeer het programma uit te voeren, eventuele fouten op te lossen en controleer het doelpad om te zien welke afbeelding is gemaakt.

The resulting image with a seed 1234
Het resulterende beeld met een zaadje van 1234

Gemak

Er zijn nog steeds enkele wijzigingen die we kunnen aanbrengen. Het eerste dat u bijvoorbeeld zou hebben opgemerkt, is dat de sterren in het midden geclusterd zijn. Om dat te verhelpen, zou je een goede formule moeten verzinnen die patronen elimineert. U kunt ook een aantal formules maken en deze afwisselen met een teller. De formules die we gebruikten waren deze:

Er is nog een eenvoudige verbetering die we kunnen implementeren. Als je naar de lucht kijkt, zie je een paar grote sterren en nog veel meer kleine sterren. In ons geval is het aantal kleine sterren echter ongeveer hetzelfde als het aantal grote sterren. Om dit op te lossen, moeten we gewoon terugkeren naar de methode getSize () in de klasse Star. Nadat we de grootte een fractie van één hebben gemaakt, moeten we dit getal verhogen tot de macht van een geheel getal - bijvoorbeeld vier of vijf.

Als u het programma voor de laatste keer uitvoert, krijgt u een bevredigend resultaat.

The final result – a whole starscape procedurally generated by our Sequence Generator!
Het eindresultaat – een volledig sterrenbeeld dat procedureel is gegenereerd door onze sequentiegenerator!

Conclusie

In dit geval hebben we een sequencegenerator gebruikt om procedureel een achtergrond te genereren. Een sequentiegenerator zoals deze kan nog veel meer gebruiken - bijvoorbeeld zou een z-coördinaat kunnen worden toegevoegd aan de ster zodat in plaats van een afbeelding te tekenen, de zou sterren zouden kunnen genereren als objecten in een 3D-omgeving.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.