[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] [Pygame] Generating a map



Hello again

Out of curosity I have written my own version, I think it should look like the attached picture.

Hope that helps. The strange thing is, that it only works with sizes that are of the numbers (2**n)+1.


~DR0ID



Kris Schnee schrieb:
Dave LeCompte (really) wrote:
Also, there's a pretty good paper about the tricks that the "Tribal
Trouble" guys used to make their terrain here:
http://oddlabs.com/download/terrain_generation.pdf

That paper was really useful. I was able to implement a version of the Voronoi (bubble/ridge thing) with some fiddling, and accidentally made what appears to be a fractal by accident. It's attached as "my_generation.py" if you want to see the messy code. The part that was hard to figure out was what the paper described as:
height = (distance to nearest point)*(arbitrary constant 1)
The distance ranges from 0 to many thousands, so what's a good way to convert that to a 0-255 range or the 0.0-1.0 range used in the paper? I ended up doing it in an arbitrary way.

I see that <http://home.scarlet.be/zoetrope/voronoi/> has a Python implementation of Voronoi code as a "Crystalize" filter for images.

I also tried to implement a diamond-square algorithm, but something's not quite right about it. If I force the squares to be higher than normal (adding 64 to the height values), I can see that it's calculating all the pixels in the image, but normally most of the image ends up black. The code for that is attached as "my_generation3.py"; anyone know how to fix it? The problem seems to be that I'm using a 256x256 bitmap, and the calculation of each cell's "neighbors" is off by one pixel or something where it wraps around the edges, so that it finds zeroed pixels instead of the already-calculated ones.

Windows bitmap




KLUDGE = 0 ## ( >0 makes the pattern visible despite being flawed )

import pygame
pygame.init()
import random
import sys
import time
import math
random.seed("Next My Generation")#+str(time.time()))
if len(sys.argv)==2:
    size = int(sys.argv[1])
else:
    size = 256

print "size:", size
good_sizes = [2**n+1 for n in range(1,20)]
if size not in good_sizes:
    n = math.log(size, 2)
    print n
    size = good_sizes[int(math.floor(n))-1]
    print "WARNING: only works with sizes (2**n)+1, size changed to:", size
    print "\ngood sizes are:", good_sizes
    print "\n"

screen = pygame.display.set_mode((size,size))
screen.fill((64,0,0))

    
def DisplayAsImage(heightmap, iteration):
    screen.fill((255,0,255))
    terrain = pygame.surface.Surface((size,size))
    terrain.fill((255,0,255))
    for y in range(size):
        for x in range(size):
            h = heightmap[(x,y)]
            if h!=-1:
                terrain.set_at((x,y),(h,h,h))
            elif iteration > 4:
##                print "ARG:", x,y
                pass
    screen.blit(terrain,(0,0))
    pygame.image.save(terrain, 'gen_terrain_'+str(size)+'x'+str(size)+'_iter'+str(iteration)+'.bmp')
    pygame.display.update()

# generate hightmap
heightmap = {}
for x in range(size):
    for y in range(size):
        heightmap[(x,y)] = -1
# fill in corners
for point in ((0,0),(size-1,0),(0,size-1),(size-1,size-1)):
    heightmap[point] = random.randint(0,255)
# override corners manually
##heightmap[(0,0)] = 0 #random.randint(0,255)
##heightmap[(size-1,0)] = 2 #random.randint(0,255)
##heightmap[(0,size-1)] = 4 #random.randint(0,255)
##heightmap[(size-1,size-1)] = 8 #random.randint(0,255)

cell_size = size
half_cell_size = cell_size/2
chaos = 255
iteration = 0
offset = KLUDGE


while cell_size > 1:
    print "---------------->iteration:", iteration
    print "cell_size", cell_size
    print "half cell size", half_cell_size
                    
    for anchy in range(0, size-cell_size+1, cell_size):
        for anchx in range(0, size-cell_size+1, cell_size):
            posx = anchx + half_cell_size
            posy = anchy + half_cell_size
            neighbors = [(posx+half_cell_size, posy+half_cell_size),\
                     (posx-half_cell_size, posy+half_cell_size),\
                     (posx+half_cell_size, posy-half_cell_size),\
                     (posx-half_cell_size, posy-half_cell_size)]
##            print anchx, anchy, posx, posy, neighbors
            sum = 0
            for n in neighbors:
                sum += heightmap[n]
            average = sum/4
            average += offset
            average += random.randint(-chaos, chaos)
            heightmap[(posx, posy)] = max(min(average, 255), 0)

    for anchy in range(0, size+1, cell_size):
        for anchx in range(0, size+1, cell_size):
#            print posx, posy, average, neighbors
            points = [(anchx+half_cell_size, anchy),\
                     (anchx, anchy+half_cell_size),\
                     (anchx+cell_size, anchy+half_cell_size),\
                     (anchx+half_cell_size, anchy+cell_size)]
            for point in points:
                px, py = point
                neighbors2 = [(px+half_cell_size, py),\
                             (px-half_cell_size, py),\
                             (px, py+half_cell_size),\
                             (px, py-half_cell_size)]
                sum = 0
                for neigh in neighbors2:
                    posx, posy = neigh
                    if posx<0:
                        posx %= size
                    if posx>size-1:
                        posx %= size
                    if posy<0:
                        posy %= size
                    if posy>size-1:
                        posy %= size
                    sum += heightmap[(posx, posy)]
                sum /= 4
                sum += random.randint(-chaos, chaos)
                sum += offset
                heightmap[(px, py)] = max(min(sum, 255), 0)
        
                    
    iteration += 1
    cell_size /= 2
    half_cell_size = cell_size/2
    
    chaos = max(chaos/2,1)
    DisplayAsImage(heightmap, iteration)
    
print "Done!"
pygame.event.set_blocked([pygame.MOUSEMOTION, pygame.ACTIVEEVENT])
pygame.event.clear()
pygame.event.wait()
##print heightmap[(0,0)], heightmap[(1,0)], heightmap[(2,0)]
##print heightmap[(0,1)], heightmap[(1,1)], heightmap[(2,1)]
##print heightmap[(0,2)], heightmap[(1,2)], heightmap[(2,2)]