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

Re: [pygame] [Pygame] Generating a map



Hi

I have looked into it and got the attached image (I do not know if you expected that, I think not, although one can see the structure). You were mistaken in edge_points (about line 77). Please look what I have changed in the attached version.

~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.

PNG image

"""
Terrain generator using diamond-square algorithm.
Something is not quite right here, because the points in one phase or
the other are off by one, causing them to find zero values instead of the
points they're supposed to find. I'm using a 256x256 map, which maybe should
be 255x255, but am not quite sure how it's meant to work.
"""

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

import pygame
pygame.init()
import random
random.seed("Next My Generation")
size = 256
screen = pygame.display.set_mode((size,size))
screen.fill((64,0,0))

def DisplayAsImage(heightmap):
    screen.fill((64,0,0))
    terrain = pygame.surface.Surface((size,size))
    terrain.fill((0,0,0))
    for y in range(size):
        for x in range(size):
            h = heightmap[x][y]
            terrain.set_at((x,y),(h,h,h))

    screen.blit(terrain,(0,0))
    pygame.image.save(terrain, 'gen_terrain3.png')
    pygame.display.update()


heightmap = []
for x in range(size):
    heightmap.append([])
    for y in range(size):
        heightmap[-1].append(0)
##        heightmap[-1].append(random.randint(0,255)) ## Placebo.
for point in ((0,0),(size-1,0),(0,size-1),(size-1,size-1)):
    heightmap[point[0]][point[1]] = 128


cell_size = size
half_cell_size = cell_size/2
chaos = 64
iteration = 0

while cell_size > 0:
##for n in range(1):
    print "Iteration: "+str(iteration)
    iteration += 1
    for anchor_y in range(0,size,cell_size):
        for anchor_x in range(0,size,cell_size):
##            print "Anchor: "+str((anchor_x,anchor_y))
            center_x = anchor_x - 1 + half_cell_size
            center_y = anchor_y - 1 + half_cell_size

            ## The "square" phase: calculate the center point.
##            print "Center: "+str((center_x, center_y))

            neighbors = ((anchor_x,anchor_y),
                         (anchor_x+cell_size-1,anchor_y),
                         (anchor_x,anchor_y+cell_size-1),
                         (anchor_x+cell_size-1,anchor_y+cell_size-1))

            try:
                average_height = sum((heightmap[n[0]][n[1]] for n in neighbors))/4
            except:
                print neighbors
                raise "Oof."
##            print "Average: "+str(average_height)
            h = average_height + random.randint(-chaos,chaos)+KLUDGE
            h = max(min(h,255),0) ## Keep within 0-255 range.
            heightmap[center_x][center_y] = h
            
            ## The "diamond" phase: calculate the edge points.
##            edge_points = ((center_x,0),
##                           (0,center_y),
##                           (size-1,center_y),
##                           (center_x,size-1))
            edge_points = ((center_x,center_y-half_cell_size),
                           (center_x-half_cell_size,center_y),
                           (center_x+half_cell_size,center_y),
                           (center_x,center_y+half_cell_size))
            for point in edge_points:
##                print "Edge point: "+str(point)
##                neighbors = [(point[0],point[1]-half_cell_size),
##                             (point[0]-half_cell_size,point[1]),
##                             (point[0]+half_cell_size,point[1]),
##                             (point[0],point[1]+half_cell_size)]
                neighbors = [[point[0],point[1]-half_cell_size],
                             [point[0]-half_cell_size,point[1]],
                             [point[0]+half_cell_size,point[1]],
                             [point[0],point[1]+half_cell_size]]
                for n in range(4):
                    neighbor = neighbors[n]
                    if neighbor[0] < 0:
                        neighbors[n][0] += size
                    elif neighbor[0] > 255:
                        neighbors[n][0] -= size
                    if neighbor[1] < 0:
                        neighbors[n][1] += size
                    elif neighbor[1] > 255:
                        neighbors[n][1] -= size



##                ## Kludge to keep first-round points within bounds.
##                if neighbors[2][0] >= size:
##                    neighbors[2] = (point[0]-half_cell_size-1,point[1])
##                if neighbors[3][1] >= size:
##                    neighbors[3] = (point[0],point[1]-half_cell_size-1)
##                print "  Neighbors: "+str(neighbors)
                try:
                    average_height = sum((heightmap[n[0]][n[1]] for n in neighbors))/4
                except:
                    print neighbors
                    raise "Eek!"
                h = average_height + random.randint(-chaos,chaos)
                h = max(min(h,255),0) ## Keep within 0-255 range.
                heightmap[point[0]][point[1]] = h

    cell_size /= 2
    half_cell_size /= 2
    chaos = max(chaos/2,1)
    DisplayAsImage(heightmap)

print "Done!"
raw_input()