[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()