-
Notifications
You must be signed in to change notification settings - Fork 264
/
terrain.py
148 lines (128 loc) · 3.93 KB
/
terrain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from pdb import set_trace as T
from opensimplex import OpenSimplex
gen = OpenSimplex()
from forge.blade.lib import enums
from matplotlib import pyplot as plt
from scipy.misc import imread, imsave
from shutil import copyfile
from copy import deepcopy
import numpy as np
import os
template_tiled = """<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" tiledversion="1.1.5" orientation="orthogonal" renderorder="right-down" width="{0}" height="{1}" tilewidth="128" tileheight="128" infinite="0" nextobjectid="1">
<tileset firstgid="0" source="../../tiles.tsx"/>
<layer name="Tile Layer 1" width="{0}" height="{1}">
<data encoding="csv">
{2}
</data>
</layer>
</map>"""
def saveTiled(dat, path):
""""Saved a map into into a tiled compatiable file given a save_path,
width and hieght of the map, and 2D numpy array specifiying enums for the array"""
height, width = dat.shape
dat = str(dat.ravel().tolist())
dat = dat.strip('[').strip(']')
with open(path + 'map.tmx', "w") as f:
f.write(template_tiled.format(width, height, dat))
#Bounds checker
def inBounds(r, c, shape, border=0):
R, C = shape
return (
r > border and
c > border and
r < R - border - 1 and
c < C - border - 1
)
def noise(nx, ny):
# Rescale from -1.0:+1.0 to 0.0:1.0
return gen.noise2d(nx, ny) / 2.0 + 0.5
def sharp(nx, ny):
return 2 * (0.5 - abs(0.5 - noise(nx, ny)));
def perlin(nx, ny, octaves, scale=1):
val = 0
for mag, freq in octaves:
val += mag * noise(scale*freq*nx, scale*freq*ny)
return
def ridge(nx, ny, octaves, scale=1):
val = []
for idx, octave in enumerate(octaves):
mag, freq = octave
v = mag*sharp(scale*freq*nx, scale*freq*ny)
if idx > 0:
v *= sum(val)
val.append(v)
return sum(val)
def expParams(n):
return [(0.5**i, 2**i) for i in range(n)]
def norm(x, X):
return x/X - 0.5
def grid(X, Y, n=8, scale=1, seed=0):
terrain = np.zeros((Y, X))
for y in range(Y):
for x in range(X):
octaves = expParams(n)
nx, ny = norm(x, X), norm(y, Y)
terrain[x, y] = ridge(seed+nx, seed+ny, octaves, scale)
return terrain / np.max(terrain)
def textures():
lookup = {}
for mat in enums.Material:
mat = mat.value
tex = imread(
'resource/assets/tiles/' + mat.tex + '.png')
key = mat.tex
mat.tex = tex[:, :, :3][::4, ::4]
lookup[key] = mat
return lookup
def tile(val, tex):
if val == 0:
return tex['lava']
elif val < 0.3:
return tex['water']
elif val < 0.57:
return tex['grass']
elif val < 0.715:
return tex['forest']
else:
return tex['stone']
def material(terrain, tex, X, Y, border=9):
terrain = deepcopy(terrain).astype(object)
for y in range(Y):
for x in range(X):
if not inBounds(y, x, (Y, X), border-1):
terrain[y, x] = tex['lava']
elif not inBounds(y, x, (Y, X), border):
terrain[y, x] = tex['grass']
else:
val = float(terrain[y, x])
terrain[y, x] = tile(val, tex)
return terrain
def render(mats, path):
images = [[e.tex for e in l] for l in mats]
image = np.vstack([np.hstack(e) for e in images])
imsave(path, image)
def index(mats, path):
inds = np.array([[e.index+1 for e in l] for l in mats])
saveTiled(inds, path)
def fractal(terrain, path):
frac = (256*terrain).astype(np.uint8)
imsave(path, terrain)
nMaps, sz = 200, 64 + 16
#nMaps, sz = 1, 512 + 16
seeds = np.linspace(0, 2**32, nMaps)
scale = int(sz / 5)
root = 'resource/maps/'
tex = textures()
for i, seed in enumerate(seeds):
print('Generating map ' + str(i))
path = root + 'procedural/map' + str(i) + '/'
try:
os.mkdir(path)
except:
pass
terrain = grid(sz, sz, scale=scale, seed=seed)
tiles = material(terrain, tex, sz, sz)
fractal(terrain, path+'fractal.png')
render(tiles, path+'map.png')
index(tiles, path)