[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] [Pygame] Generating a map
> talking a little recently about random terrain generation. One technique
> worth looking at is "Perlins noise," one way of implementing which is to
> draw various surfaces full of random data, overlay them with different
> "weights," and use the result to decide gameplay features such as the
> height of terrain.
After a LOT of trial and error, I managed to implement a proper Perlin
noise routine and draw a heightfield with it. Run main2D.py. I was
surprised at how slow it is.
Alan
#http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
#~ http://www.noisemachine.com/talk1/17.html
import random
import math
#===============================================================
p=[x for x in range(100)]
random.shuffle(p)
rg=[x/16.0 for x in range(100)]
random.shuffle(rg)
g=[ (math.cos(x), math.sin(x) ) for x in rg]
def noiser(x):
return g[x % 100]
def noiser2(x,y):
return g[ ( x + p[y%100] ) %100 ]
#===============================================================
#===============================================================
#===============================================================
def interpolatednoiser(n):
intn = int(n)
fracn = n - intn
v1=noiser(intn) / 100.0
v2=noiser(intn + 1) / 100.0
ft = fracn * math.pi #cos interp
f = (1.0 - math.cos(ft)) * .5
return v1*(1-f) + v2*f
def interpolatednoiser2(x, y):
intx = int(x)
fracx = x - intx
inty = int(y)
fracy = y - inty
gx, gy = noiser2(intx, inty)
v1 = (gx*fracx) + (gy*fracy)
gx, gy = noiser2(intx + 1, inty)
v2 = (gx*(fracx-1)) + (gy*fracy)
gx, gy = noiser2(intx, inty +1)
v3 = (gx*fracx) + (gy*(fracy-1))
gx, gy = noiser2(intx + 1, inty + 1)
v4 = (gx*(fracx-1)) + (gy*(fracy-1))
ftx = fracx * math.pi #cos interp
fx = (1.0 - math.cos(ftx)) * .5
midx1= v1*(1-fx) + v2*fx
midx2 = v3*(1-fx) + v4*fx
fty = fracy * math.pi #cos interp
fy = (1.0 - math.cos(fty)) * .5
return (midx1*(1.0-fy)) + (midx2 * fy)
#===============================================================
#===============================================================
#===============================================================
def perlin1(x,oct=6,per=0.7):
total=0
j=0
for i in range(oct):
freq = 2**i
amp = per**(i*2)
j = interpolatednoiser( x * freq) * amp
total += j
return total
def perlin2(x, y, oct=6,per=0.9):
total=0
for i in range(oct):
freq = 2**i
amp = per**i #(i*2)
total += interpolatednoiser2( x * freq, y*freq) * amp
return total
#===============================================================
#===============================================================
#===============================================================
def testperlin1():
for x in range(25):
y=perlin1(x, 4)
z=int(y*50)
print y
def testperlin2():
for y in range(10):
row = []
for x in range(10):
z = perlin2(x/4.0,y/4.0, 4)
row.append(z)
print "%3.3f" %(z,),
print
if __name__ == "__main__":
#print p
#print g
#testperlin1()
testperlin2()
import pygame
import math
from pygame.locals import *
import perlin
def main():
pygame.init()
screen = pygame.display.set_mode((1024,768) )
stretch=50.0
zoom=6
octaves=4
persist=0.7
minc=255
maxc=0
screen.fill( (0,0,0) )
for y in range(400):
for x in range (400):
p=perlin.perlin2(x/stretch, y/stretch, octaves, persist ) #*(y/400.0) )
z = p*170 +128 #- 30 #classic
c=int(z)
if c>maxc:
maxc=c
if c<minc:
minc=c
if c>255:
c=255
if c<=0:
c=0
pygame.draw.line(screen, (c,c,c), (x+y/3, y + 20), (x+y/3, y + (20-(z/4))) ) #grayscale
screen.set_at( (x+512,y), (c,c,c) )
pygame.display.update()
event = pygame.event.poll()
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
break
print "minc:", minc, " maxc:",maxc
while 1:
event = pygame.event.wait()
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
break
if (event.type == KEYDOWN and event.key == K_o):
octaves += 1
main()