 |
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Ice
Anmeldungsdatum: 15.02.2014 Beiträge: 4
|
Verfasst am: 25.03.2014, 22:03 Titel: mit "PerlinNoise"-Function ein 2D-Array füllen |
|
|
Hallo zusammen,
ich versuche im Moment eine sogenannte Tilemap mithilfe der PerlinNoise Funktion zu erstellen.
Fürs besser Verständnis gehe ich jetzt einfach mal der Reihe nach durch:
Ohne PerlinNoise, mit "normalen" Zufallszahlen klappt es ganz gut, eine Tilemap zu erstellen.
Der Folgende Code füllt mir ein 2-dimensionales Array mit Zufallszahlen und lädt anhand der zufälligen Zahlen entweder die gras.bmp oder erde.bmp nebeneinander und untereinander auf der Bildschirm, sodass eine zufällige "Karte" ensteht.
Code: |
DIM array(60, 60) AS DOUBLE
DIM erde AS any ptr
DIM gras AS any ptr
Screen 18,24,2,0
RANDOMIZE
FOR y AS INTEGER = 0 TO 31
FOR x AS INTEGER = 0 TO 42
array(x, y) = RND*2
IF array(x, y) <= 0.4 THEN
erde = IMAGECREATE (16,16)
BLOAD "erde.bmp", 0
GET (0,0)-(15,15), erde
PUT (x*15, y*15), erde, PSET
ELSE
grass = Imagecreate (16,16)
BLOAD "gras.bmp", 0
GET (0,0)-(15,15), gras
PUT (x*15, y*15), gras, PSET
END IF
NEXT
NEXT
|
Das Problem, mit dieser "Zufallskarte" ist allerdings zunächst, dass sie keine "logisch" zusammenhängenden Flächen aufweist, da die Punkte wirklich komplett zusammenhangslos verteilt werden
An dieser Stelle kommt "PerlinNoise" ins Spiel.
Deswegen habe ich ein paar Tage recherchiert und unter anderem folgenden FreeBasic-Code für eben jenes PerlinNoise gefunden (bei Rückfragen dazzu am besten googeln, da ich selber das Prinzip erst so halbwegs verstanden habe):
Code: | dim as integer screen_width = 800, screen_height = 600
screenres screen_width, screen_height, 32, 0, 0
function Interpolate(i as single, j as single, k as single) as single
return (1-k)*i + k*j
end function
function Noise(x as integer, y as integer) as single
dim as integer n
n = x + y * 57
n = (n shl 13) xor n
return (1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) and &H7fffffff) / 1073741824.0)
end function
function SmoothNoise(x as integer, y as integer) as single
dim as single corners, sides, center
corners = (Noise(x-1, y-1) + Noise(x+1, y-1) + Noise(x-1, y+1) + Noise(x+1, y+1) ) / 16
sides = (Noise(x-1, y) + Noise(x+1, y) + Noise(x, y-1) + Noise(x, y+1) ) / 8
center = Noise(x, y) / 4
return corners + sides + center
end function
function InterpolatedNoise(x as single, y as single) as single
dim as integer integer_X, integer_Y
dim as single v1, v2, v3, v4, i1, i2, fractional_X, fractional_Y
integer_X = int(x)
fractional_X = x - integer_X
integer_Y = int(y)
fractional_Y = y - integer_Y
v1 = SmoothNoise(integer_X, integer_Y)
v2 = SmoothNoise(integer_X + 1, integer_Y)
v3 = SmoothNoise(integer_X, integer_Y + 1)
v4 = SmoothNoise(integer_X + 1, integer_Y + 1)
i1 = Interpolate(v1 , v2 , fractional_X)
i2 = Interpolate(v3 , v4 , fractional_X)
return Interpolate(i1 , i2 , fractional_Y)
end function
function PerlinNoise(x as single,y as single) as single
dim as single frequency, amplitude
dim as single total = 0
dim as single p = 1 'persistence
dim as integer n = 10 ' Number_Of_Octaves
for i as integer = 1 to n
frequency = 2*i
amplitude = p/i
total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude
next i
return total
end function
for i as integer = 0 to screen_width-1
for j as integer = 0 to screen_height-1
dim as Single PN = (PerlinNoise(i/16,j/16) + 1)/2
pset (i,j), RGB(PN * 255, PN * 255, PN * 255)
next j
next i |
Dieser Code funktioniert an sich und zeichnet mit der letzten "for i/for j"-Schleife folgendes auf den Bildschirm:
Also ganz in dem Sinne, wie PerlinNoise aussehen soll!
So, lange Rede und kaum kein Sinn
Hat jemand eine Idee, wie ich die Werte, die mir "function PerlinNoise" berechnet, anstatt als Zeichnung in ein zweidimensionales Array einbinden kann? Damit ich anschließend wieder, wie gehabt, durch IF...THEN bestimmten Wertebereichen eine *.bmp zuweisen und anschließend laden kann?
Wenn ich das richtig verstehe, müsste "function PerlinNoise" ja bloß immer einen zufälligen Endwert "total" berechnen, oder?
Wie rufe ich den Wert in meinem anfänglichen Code auf?
Oder bin ich mit meinem zweidimensionalen Array hierbei völlig auf dem Holzweg?? Ich bin sehr gespannt auf eure Rückmeldungen!
Beste Grüße
Ice |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 25.03.2014, 22:53 Titel: |
|
|
vielleicht gibt das den richtigen denk-anstoss
Code: |
'...
for i as integer = 0 to screen_width-1
for j as integer = 0 to screen_height-1
dim as Single PN = (PerlinNoise(i/16,j/16) + 1)/2
Print i; "x"; j; "="; PN * 255
next j
next i
|
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
Ice
Anmeldungsdatum: 15.02.2014 Beiträge: 4
|
Verfasst am: 25.03.2014, 23:28 Titel: |
|
|
Allerdings!! 1 to screenwidth war zwar ein bisl heftig, aber bis 50 reichte mir auch schon
Besten Dank, nun läufts schonmal!
(Jetzt tun sich gleich andere Probleme auf mit Feintuning und jedesmal zufälliger Erstellung vom Noise, aber das ist eine andere Geschichte und ein anderer Programmierabend ) |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 25.03.2014, 23:48 Titel: |
|
|
Aber, um ne relativ "smoothe" karte zu erzeugen kannst du eigentlich auch recht einfach vorgehen. Dafür erzeugst du einfach eine rauschende Karte (rnd * 255), und legst darüber dann einen weichzeichner.
Die "körnigkeit" beeinflust du durch die Art des rauschens. z.B. Pixel rnd's, circle rnd's, rect Rnd's, ...
Code: |
pset, map, ((int(rnd() * breite), int(rnd() * höhe)), int(rnd() * 255)
circle, map, ((int(rnd() * breite), int(rnd() * höhe)), int((rnd() * maxkreisbreite) + 1), int(rnd() * 255)
'...
|
je gröser die monofarbenen flächen, desto smoother wirds. je kleiner, desto gröber.
zum schluss den weichzeichner grüber, und fertig isses.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
Haubitze
Anmeldungsdatum: 14.10.2009 Beiträge: 132
|
Verfasst am: 26.03.2014, 00:59 Titel: |
|
|
Hi Ice,
du koenntest ja deine function
Code: |
function Noise(x as integer, y as integer) as single
dim as integer n
n = x + y * 57
n = (n shl 13) xor n
return (1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) and &H7fffffff) / 1073741824.0)
end function
|
um einen parameter erweitern der den seed angiebt somit kannst du immer genau die selbe karte erstellen
Code: |
function Noise(x as integer, y as integer,seed as uinteger) as single
dim as integer n
n = x + y * 57+seed
n = (n shl 13) xor n
return (1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) and &H7fffffff) / 1073741824.0)
end function
|
auswerten wuerd ich das wie ThePuppetMaster in seiner ersten antwort schrieb
Code: |
...
dim as Single PN = ((PerlinNoise(i/16,j/16) + 1)/2)*255
...
select case PN
case 1 to 10
DrawTile(ERDE)
case 11 to 200
DrawTile(WASSER)
...
...
|
Salute |
|
Nach oben |
|
 |
Ice
Anmeldungsdatum: 15.02.2014 Beiträge: 4
|
Verfasst am: 26.03.2014, 09:25 Titel: |
|
|
Puppet Master, meinst du mit Weichzeichner einen im Grafikprogramm?
Das würde dann allerdings nicht weiterhelfen, weil es mir ja darum geht, Zahlenwerte mit Noise zu versehen und nicht einfach ein rauschendes Bild zu erstellen...
Haubitze, klingt gut mit dem seed! |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 26.03.2014, 12:25 Titel: |
|
|
Nun ... so wie ich das verstanden habe, willst du ne map erstellen. eine "random" map, die du erneut erzeugen kannst. Das kann man durchaus so machen. Mit randomize(<wert>) kann man einen startwert festlegen, mit dessen hilfe sich diese "zufallskarte" immer wieder erzeugen lässt.
Weichzeichner: Jain .. also .. das prinzip is wie bei nem grafik-prog, nur das du es halt in deinem programm automatisiert machst, um den "smoothness" zu erzeugen.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
|
Nach oben |
|
 |
Ice
Anmeldungsdatum: 15.02.2014 Beiträge: 4
|
Verfasst am: 27.03.2014, 11:29 Titel: |
|
|
Puuh, ganz schön viel Code für die Civ-Maps ...
Das kreiert natürlich super Weltkarten! Für meine Zwecke und fürn Anfang will ich eher Karten von "Gebieten" (im Stile von zB. AoE/AoE2) als von ganzen Kontinenten erzeugen. Also ein paar zusammenhängende Wälder, Seen und Berge reichen schon
Edit: Echt hammer wie die PerfectWorld Generatoren sogar berücksichtigen, dass hohe Berge den Niederschlag abfangen und auf der anderen Seite dadurch Trockengebiete entstehen! |
|
Nach oben |
|
 |
Muttonhead

Anmeldungsdatum: 26.08.2008 Beiträge: 565 Wohnort: Jüterbog
|
|
Nach oben |
|
 |
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|