├── .gitignore ├── Classes.py ├── Map.py ├── MapGenerator.py ├── PythonApplication2.pyproj ├── README.md ├── VectorMath.py ├── _Generators.py └── __pycache__ ├── Classes.cpython-35.pyc ├── Generators.cpython-35.pyc ├── Map.cpython-35.pyc ├── MapGenerator.cpython-35.pyc ├── VectorMath.cpython-35.pyc └── _Generators.cpython-35.pyc /.gitignore: -------------------------------------------------------------------------------- 1 | *.png 2 | generated.png -------------------------------------------------------------------------------- /Classes.py: -------------------------------------------------------------------------------- 1 | class Color: 2 | 3 | # 0 -> 255 4 | 5 | r = 0.0; 6 | g = 0.0; 7 | b = 0.0; 8 | a = 1.0; 9 | 10 | def __init__(self, r = 0.0, g = 0.0, b = 0.0): 11 | self.r = r; 12 | self.g = g; 13 | self.b = b; 14 | self.a = 1; 15 | def GetTuple(self): 16 | return (int(self.r),int(self.g),int(self.b)); 17 | def SetColor(self, r, g, b): 18 | self.r = r; 19 | self.g = g; 20 | self.b = b; 21 | def Copy(self, color): 22 | self.r = color.r; 23 | self.g = color.g; 24 | self.b = color.b; 25 | def SetWhite(self): 26 | self.SetColor(1,1,1); 27 | def SetBlack(self): 28 | self.SetColor(0,0,0); 29 | def SetColorFromGrayscale(self, f = 0.0): 30 | self.SetColor(f,f,f); 31 | 32 | paperColor = Color(212, 161, 104); 33 | waterColor = Color(0, 20, 28); 34 | 35 | -------------------------------------------------------------------------------- /Map.py: -------------------------------------------------------------------------------- 1 | from Classes import * 2 | import random 3 | 4 | perlinOffset = random.random()*2048; # random offset 5 | 6 | mapSize = 2048; # size in pixels 7 | perlinScale = 0.0025; 8 | mapCenter = (mapSize/2, mapSize/2); 9 | 10 | landThreshold = 0.1; 11 | 12 | heightMap = [[0]*mapSize for x in range(mapSize)] 13 | colorMap = [[Color() for j in range(mapSize)] for i in range(mapSize)] 14 | 15 | randomColorRange = 10; 16 | colorPerlinScale = 0.025; -------------------------------------------------------------------------------- /MapGenerator.py: -------------------------------------------------------------------------------- 1 | print("Setting up... \n"); 2 | 3 | from PIL import Image 4 | 5 | from Map import * 6 | from _Generators import * 7 | from Classes import * 8 | from VectorMath import * 9 | 10 | image = Image.new("RGB", (mapSize,mapSize)) 11 | targetGenerator = None 12 | 13 | # future multiproc stuff 14 | 15 | #import multiprocessing 16 | # 17 | # 18 | #def worker(index): 19 | # print("worker spawned ",index) 20 | # while(True): 21 | # if (targetGenerator == None or targetGenerator.isFinished): 22 | # break; 23 | # targetGenerator.GenerateAutomated(); 24 | # for x in range(0, mapSize): 25 | # for y in range(0, mapSize): 26 | # im.putpixel((x,y), colorMap[x][y].GetTuple()); 27 | 28 | #threadsAmount = 1 29 | #threads = [] 30 | 31 | #if __name__ == '__main__': 32 | 33 | # for i in range(threadsAmount): 34 | # print("starting process ", i); 35 | # t = multiprocessing.Process(target=worker, args=(i,)) 36 | # threads.append(t) 37 | # t.start() 38 | 39 | # for i in range(threadsAmount): 40 | # threads[i].join(); 41 | 42 | targetGenerator = MapGen_Main(); 43 | 44 | print("Generating... \n"); 45 | 46 | targetGenerator.GenerateFull(); 47 | 48 | print("\n\nGeneration finished. Saving output as Generated.png."); 49 | 50 | for x in range(0, mapSize): 51 | for y in range(0, mapSize): 52 | image.putpixel((x,y), colorMap[x][y].GetTuple()); 53 | 54 | image.save("Generated.png"); 55 | image.show(); 56 | -------------------------------------------------------------------------------- /PythonApplication2.pyproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | 2.0 6 | 4510984d-d54c-4d27-afaf-8170b3504e71 7 | . 8 | MapGenerator.py 9 | 10 | 11 | . 12 | . 13 | PythonApplication2 14 | PythonApplication2 15 | 16 | 17 | true 18 | false 19 | 20 | 21 | true 22 | false 23 | 24 | 25 | 26 | Code 27 | 28 | 29 | Code 30 | 31 | 32 | Code 33 | 34 | 35 | 36 | Code 37 | 38 | 39 | 40 | 10.0 41 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python-Map-Generator 2 | Generates procedural maps using perlin noise. My first python project 3 | 4 | Example of a generated map: 5 | 6 | ![alt tag](http://i.imgur.com/7ZK6EG8.png) 7 | -------------------------------------------------------------------------------- /VectorMath.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def Distance(ax = 0.0, ay = 0.0, bx = 0.0, by = 0.0): 4 | x = ax - bx; 5 | x *= x; 6 | y = ay - by; 7 | y*= y; 8 | return (math.sqrt(x + y)); 9 | 10 | def DistanceNormalized(ax = 0.0, ay = 0.0, bx = 0.0, by = 0.0, size = 256): 11 | dist = Distance(ax, ay, bx, by); 12 | dist /= size; 13 | return dist; -------------------------------------------------------------------------------- /_Generators.py: -------------------------------------------------------------------------------- 1 | from noise import snoise2; 2 | import math 3 | from tqdm import tqdm 4 | import random 5 | 6 | from Classes import * 7 | from VectorMath import * 8 | from Map import * 9 | 10 | class MapGen_Base: 11 | 12 | def __init__(self): # Constructor of the class 13 | self.progress = 0; 14 | self.totalProgress = mapSize * mapSize; 15 | self.isFinished = False; 16 | self.pbar = tqdm(total = mapSize * mapSize); 17 | self.pbar.clear(); 18 | self.smartGenerationEnabled = False; 19 | self.x = 0; 20 | self.y = 0; 21 | 22 | def GeneratePixel(self, x, y): # generate one pixel 23 | self.x += 1; 24 | if (self.x >= mapSize): 25 | self.x = 0; 26 | self.y += 1; 27 | if (self.y >= mapSize): 28 | self.isFinished = True; 29 | self.pbar.close(); 30 | print(x + " " + y); 31 | 32 | def GenerateSmart(self): # will be used for multiprocessing 33 | self.smartGenerationEnabled = True; 34 | self.GeneratePixel(self.x,self.y); 35 | 36 | def GenerateFull(self): # fully generate 37 | for x in range(0, mapSize): 38 | for y in range(0, mapSize): 39 | self.Generate(x,y); 40 | 41 | class MapGen_Main(MapGen_Base): # get base perlin height, make terrain and water 42 | 43 | def Generate(self, x, y): 44 | 45 | if (self.smartGenerationEnabled): 46 | self.x += 1; 47 | if (self.x >= mapSize): 48 | self.x = 0; 49 | self.y += 1; 50 | if (self.y >= mapSize): 51 | self.isFinished = True; 52 | self.pbar.close(); 53 | 54 | basePerlinValue = (snoise2(float(x)*perlinScale, float(y)*perlinScale, octaves=8, persistence=0.5, lacunarity=2.0, repeatx=2048, repeaty=2048, base=perlinOffset) + 1)/2.0; 55 | 56 | ## pixel height 57 | 58 | distance = DistanceNormalized(x,y, mapCenter[0], mapCenter[1], mapSize); 59 | 60 | basePerlinValue -= math.pow(distance, 0.5); 61 | if (basePerlinValue <= 0): 62 | basePerlinValue = 0; 63 | 64 | heightMap[x][y] = basePerlinValue; 65 | 66 | ## pixel color 67 | 68 | if (heightMap[x][y] > landThreshold): # land 69 | 70 | detailPerlinValue = (snoise2(float(x)*perlinScale, float(y)*perlinScale, octaves=12, persistence=0.8, lacunarity=2.0, repeatx=2048, repeaty=2048, base=perlinOffset) + 1)/2.0; 71 | 72 | normalizedHeight = (detailPerlinValue - landThreshold); 73 | normalizedHeight *= normalizedHeight*normalizedHeight; # normalized height ^3 74 | 75 | noiseValue = (snoise2(float(x)*colorPerlinScale, float(y)*colorPerlinScale, octaves=2, persistence=0.5, lacunarity=2.0, repeatx=2048, repeaty=2048, base=perlinOffset) + 1)/2.0; 76 | randomColorOffset = (random.random()-0.5)*8 + 24.0*noiseValue + normalizedHeight*256.0; 77 | 78 | r = paperColor.r + randomColorOffset; 79 | g = paperColor.g + randomColorOffset; 80 | b = paperColor.b + randomColorOffset; 81 | colorMap[x][y].SetColor(r,g,b); 82 | 83 | else: # water 84 | 85 | #detailPerlinValue = (snoise2(float(x)*perlinScale, float(y)*perlinScale, octaves=12, persistence=0.8, lacunarity=2.0, repeatx=2048, repeaty=2048, base=perlinOffset) + 1)/2.0; 86 | 87 | #normalizedHeight = (detailPerlinValue - landThreshold); 88 | #normalizedHeight *= normalizedHeight*normalizedHeight; # normalized height ^3 89 | 90 | normalizedHeight = (heightMap[x][y]); 91 | #normalizedHeight *= normalizedHeight; 92 | 93 | if (normalizedHeight < 0): 94 | normalizedHeight = 0; 95 | 96 | waterNoisePerlinScale = 0.01; 97 | 98 | noiseValue = (snoise2(float(x)*waterNoisePerlinScale, float(y)*waterNoisePerlinScale, octaves=2, persistence=0.5, lacunarity=2.0, repeatx=2048, repeaty=2048, base=perlinOffset) + 1)/2.0; 99 | randomColorOffset = (random.random()-0.5)*4 + 12.0*noiseValue + normalizedHeight*96.0; 100 | 101 | r = waterColor.r + randomColorOffset; 102 | g = waterColor.g + randomColorOffset; 103 | b = waterColor.b + randomColorOffset; 104 | 105 | if (r < 0): 106 | r = 0; 107 | if (g < 0): 108 | g = 0; 109 | if (b < 0): 110 | b = 0; 111 | 112 | colorMap[x][y].SetColor(r,g,b); 113 | 114 | self.pbar.update(1); # update progress bar -------------------------------------------------------------------------------- /__pycache__/Classes.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artnas/Python-Map-Generator/a9608f9430d1a3cb9a70609d6b6863c4902bfb65/__pycache__/Classes.cpython-35.pyc -------------------------------------------------------------------------------- /__pycache__/Generators.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artnas/Python-Map-Generator/a9608f9430d1a3cb9a70609d6b6863c4902bfb65/__pycache__/Generators.cpython-35.pyc -------------------------------------------------------------------------------- /__pycache__/Map.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artnas/Python-Map-Generator/a9608f9430d1a3cb9a70609d6b6863c4902bfb65/__pycache__/Map.cpython-35.pyc -------------------------------------------------------------------------------- /__pycache__/MapGenerator.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artnas/Python-Map-Generator/a9608f9430d1a3cb9a70609d6b6863c4902bfb65/__pycache__/MapGenerator.cpython-35.pyc -------------------------------------------------------------------------------- /__pycache__/VectorMath.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artnas/Python-Map-Generator/a9608f9430d1a3cb9a70609d6b6863c4902bfb65/__pycache__/VectorMath.cpython-35.pyc -------------------------------------------------------------------------------- /__pycache__/_Generators.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artnas/Python-Map-Generator/a9608f9430d1a3cb9a70609d6b6863c4902bfb65/__pycache__/_Generators.cpython-35.pyc --------------------------------------------------------------------------------