top of page

Python: Top-Down Procedural Generation

  • Writer: Max Clark
    Max Clark
  • Jan 8, 2017
  • 3 min read

This post poses a new simple way to create procedural generation in python. This is an alternative to Perlin noise.

The concept involves casting dots onto a two dimensional plane; for every pixel in the plane, the number of dots within a certain radius is counted. The value for this count will be the altitude, giving a third dimension.

First, we need to import some libraries:

import pygame import math import random from random import randint

Here are the necessary variables:

#Settings size = 80 #count radius, controls biome size pixel = 2 #controls resolution k = 1.0 #relative altitude (0.6 < x < 1.5, for best results) grass = 30 #color level rock = 44 # '' '' snow = 48 # '' ''

dotsx = [] # contains all x-coordinates for the dots dotsy = [] # contains all y-coordinates as well as the weighting

The dots require a weighting so that the dot count (and therefore altitude) is not a whole number. Now lets create a function to count the number dots within a radius around a given coordinate.

def get_count(xc, yc): count = 0

This most efficient way to do this requires the horizontal and vertical distance between the coordinate and each pixel. for i in range(len(dotsx)): dx = abs(dotsx[i] - xc) dy = abs(dotsy[i][0] - yc)

Now we use these values to see if the current dot lies within the radius (with 'size' being the radius). Please see philcolbourn's answer here for the explanation.

if dx < size: if dy < size: if dx + dy <= size: count += dotsy[i][1] elif math.pow(dx,2) + math.pow(dy,2) <= math.pow(size,2): count += dotsy[i][1]

return count

This concludes the function. Now we initiate pygame and set the window size. This can be set to any value.

pygame.init()

xSize, ySize = 400, 400 screen = pygame.display.set_mode((xSize, ySize)) pygame.display.set_caption("Noise Creation")

Next, we create the coordinates and the weighting for each dot. I have developed the formula 'k*10*(xSize+2*size)*(ySize+2*size)/math.pow(size,2)' to decide the number of dots based on the settings above. This algorithm creates dots beyond the size of the window so pixels on the edge do not automatically count fewer dots.

for _ in range(int(k*10*(xSize+2*size)*(ySize+2*size)/math.pow(size,2))): dotsx.append(randint(0,xSize+2*size)-1*size) dotsy.append([randint(0,ySize+2*size)-1*size, randint(0,200)/100])

It is now time to draw the landscape we draw squares with side length 'pixel'. The colour of the pixel is determined by the count of dots.

#Create Landscape

screen.fill([29,109,210])

for x in range(int(xSize/pixel)): x *= pixel for y in range(int(ySize/pixel)): y *= pixel

count = get_count(x, y)

if count > grass: pygame.draw.rect(screen, [60,204,62], (x,y,pixel,pixel)) if count > rock: pygame.draw.rect(screen, [91,46,39], (x,y,pixel,pixel)) if count > snow: pygame.draw.rect(screen, [255,255,255], (x,y,pixel,pixel)) pygame.display.flip()

Here is the whole code:

import pygame import math import random from random import randint

#Settings size = 80 #count radius, controls biome size pixel = 2 #controls resolution k = 1.0 #relative altitude (0.6 < x < 1.5, for best results) grass = 30 #color level rock = 44 # '' '' snow = 48 # '' ''

dotsx = [] # contains all x-coordinates for the dots dotsy = [] # contains all y-coordinates as well as the weighting

def get_count(xc, yc): count = 0

for i in range(len(dotsx)): dx = abs(dotsx[i] - xc) dy = abs(dotsy[i][0] - yc)

if dx < size: if dy < size: if dx + dy <= size: count += dotsy[i][1] elif math.pow(dx,2) + math.pow(dy,2) <= math.pow(size,2): count += dotsy[i][1]

return count

pygame.init()

xSize, ySize = 400, 400 screen = pygame.display.set_mode((xSize, ySize)) pygame.display.set_caption("Noise Creation")

for x in range(int(k*10*(xSize+2*size)*(ySize+2*size)/math.pow(size,2))): dotsx.append(randint(0,xSize+2*size)-1*size) dotsy.append([randint(0,ySize+2*size)-1*size, randint(0,200)/100])

#Create Landscape

screen.fill([29,109,210])

for x in range(int(xSize/pixel)): x *= pixel for y in range(int(ySize/pixel)):

y *= pixel count = get_count(x, y)

if count > grass: pygame.draw.rect(screen, [60,204,62], (x,y,pixel,pixel)) if count > rock: pygame.draw.rect(screen, [91,46,39], (x,y,pixel,pixel)) if count > snow: pygame.draw.rect(screen, [255,255,255], (x,y,pixel,pixel)) pygame.display.flip()

コメント


Read more:

    "Let's go invent tomorrow instead of worrying about what happened yesterday" 

                                                                                                       Steve Jobs

    computer_engineering_science_tech_3072x2048
    Computer Screens
    Modern Digital Watch
    Computer Circuit Board Macro
    Globalization concept
    Online Monitoring
    black_keyboard_lights_macbook_hi_tech_hd_wallpaper-wide

    © 2020 Tech Kingdom

    Contact Us : official.techkingdom@gmail.com

    bottom of page