Browse Source

Add base64 string representation for dungeon images

master
Josh Gordon 3 years ago
parent
commit
4146ea193e
  1. 1
      app/.gitignore
  2. 137
      app/dungeon.py

1
app/.gitignore

@ -1,2 +1,3 @@
__pycache__
generated_dungeon.png

137
app/dungeon.py

@ -3,6 +3,8 @@ from random import randint, choice
import numpy as np
import cv2
import base64
#algorithm: http://blankhead.fi/blog/index.php/2019/06/01/cell-flow-dungeon-layout-generation/
CELL_SIZE = 5
@ -12,9 +14,10 @@ MAP_SCALE = 12
SCALE_FACTOR = WALL_SCALE*MAP_SCALE
GRID_SIZE = 10
FLOW_COLOR = np.array([0,255,0]) #red
FLOW_COLOR = np.array([0,255,0]) #green
WALL_COLOR = np.array([255,255,255]) #white
FLOOR_COLOR = np.array([40,100,100]) #brown
GRID_COLOR = np.array([0,0,50]) #red
def randomColor():
b = randint(0,255)
@ -150,6 +153,55 @@ class Grid(object):
def getCells(self):
return self.cells
class DungeonSpace(object):
EMPTY = 0
FLOOR = 1
WALL = 2
MONSTER = 3
#add more things
class Dungeon(object):
#to those who read this code, I sincerely apologize for the
# _ _ _ _ _ _
# /_\ __| |_ ____ _ _ __ ___ ___ __| | /_\ _ _| |_(_)___ _ __ ___
# //_\\ / _` \ \ / / _` | '_ \ / __/ _ \/ _` | //_\\| | | | __| / __| '_ ` _ \
#/ _ \ (_| |\ V / (_| | | | | (_| __/ (_| | / _ \ |_| | |_| \__ \ | | | | |
#\_/ \_/\__,_| \_/ \__,_|_| |_|\___\___|\__,_| \_/ \_/\__,_|\__|_|___/_| |_| |_|
#
#that you are about to see
#Dungeon generation begins with a reasonable data structure, and then degrades into an opencv image
#In this __init__, we read it out of the image and back into a different data structure
def __init__(self,im,name="Generic Dungeon"):
self.name = name
self.spaces = []
w,h,_ = im.shape
for rx in range(w//MAP_SCALE):
col = []
for ry in range(h//MAP_SCALE):
x = rx*MAP_SCALE
y = ry*MAP_SCALE
if np.array_equal(im[x,y,:],np.array([0,0,0])):
col.append(DungeonSpace.WALL)
else:
col.append(DungeonSpace.FLOOR)
self.spaces.append(col)
def __str__(self):
return str(self.spaces)
def exportImage(self):
w = len(self.spaces)
h = len(self.spaces[0])
im = np.zeros((w*MAP_SCALE,h*MAP_SCALE,3))
for x in range(len(self.spaces)):
for y in range(len(self.spaces[0])):
im[x*MAP_SCALE:(x+1)*MAP_SCALE,y*MAP_SCALE:(y+1)*MAP_SCALE,:] = np.array([0,0,0]) if self.spaces[x][y] == DungeonSpace.WALL else np.array([.5,0,0])
return im
def scaleMap(im):
return np.kron(im,np.ones((MAP_SCALE,MAP_SCALE,1)))
@ -163,8 +215,8 @@ def drawWalls(im,grid):
w,h,_ = im.shape
for cell in grid.getCells():
for (cx,cy) in cell.getSpaces():
for dx in range(WALL_SCALE):
for dy in range(WALL_SCALE):
for dx in range(WALL_SCALE): #I know how this looks, but this does not vectorize
for dy in range(WALL_SCALE): #due to the neighbor checking
x = cx*WALL_SCALE+dx
y = cy*WALL_SCALE+dy
#print(x,y)
@ -176,13 +228,10 @@ def drawWalls(im,grid):
color = im[x,y,:]
floor = True
for i in [-1,0,1]:
for j in [-1,0,1]: #this works horizontally
for j in [-1,0,1]:
if not np.array_equal(im[x+i,y+j,:],color): #if a neighbor has a different color
if not np.array_equal(newim[x+i,y+j,:],WALL_COLOR): #and that color is not a wall
floor = False #become a wall
else:
pass
#print("Debug")
if not floor:
newim[x,y,:] = WALL_COLOR
return newim
@ -198,16 +247,56 @@ def carveDoors(im,grid):
def canonicalize(im):
w,h,_ = im.shape
newim = im.copy()
for x in range(w):
for y in range(h):
if np.array_equal(im[x,y,:],np.array([0,0,0])) or np.array_equal(im[x,y,:],WALL_COLOR):
pass
else:
newim[x,y,:] = FLOOR_COLOR/255
return newim
gray = cv2.cvtColor(im.astype(np.float32),cv2.COLOR_BGR2GRAY)
canonBW = cv2.inRange(gray,1/255,254/255)
canon = cv2.cvtColor(canonBW,cv2.COLOR_GRAY2BGR)
return canon,canonBW
def drawGrid(im,mask): #draws grid on canonicalized image
w,h,_ = im.shape
newim = im.copy()
for x in range(w//MAP_SCALE):
cv2.line(newim,
(x*MAP_SCALE,0),
(x*MAP_SCALE,h-1),
GRID_COLOR/255,
1) #thicc
for y in range(h//MAP_SCALE):
cv2.line(newim,
(0,y*MAP_SCALE),
(w-1,y*MAP_SCALE),
GRID_COLOR/255,
1)
gridded = cv2.bitwise_and(newim,newim,mask=mask)
return gridded
def genGridDungeonB64(gSizeX,gSizeY,mScale,imScale,numCells=None):
global MAP_SCALE
global WALL_SCALE
MAP_SCALE = mScale
WALL_SCALE = imScale//MAP_SCALE
g = Grid(gSizeX,gSizeY)
if numCells == None:
numCells = (gSizeX+gSizeY)//10
for _ in range(numCells):
g.addCell()
im = g.exportImage()
im = drawWalls(im,g)
im = carveDoors(im,g)
im = scaleMap(im)
im,mask = canonicalize(im)
im = drawGrid(im,mask)
#cv2.imshow("here",im)
#cv2.waitKey(0)
#base64 encode as jpg
ret,buf = cv2.imencode('.jpg',im)
enc = base64.b64encode(buf)
return enc
#s = genGridDungeonB64(10,10,8,24)
#print(s)
"""
#driver code
g = Grid(GRID_SIZE,GRID_SIZE)
g.addCell()
@ -226,9 +315,17 @@ im = drawWalls(im,g)
im = carveDoors(im,g)
im = scaleMap(im)
#drawFlow(im,g)
im = canonicalize(im)
im,mask = canonicalize(im)
drawn = drawGrid(im,mask)
cv2.imshow("Here",im)
cv2.waitKey(0)
#cv2.imshow("Here",drawn)
#cv2.waitKey(0)
cv2.imwrite("generated_dungeon.png",im)
cv2.imwrite("generated_dungeon.png",drawn)
d = Dungeon(im)
print(d)
res = d.exportImage()
cv2.imshow("res",res)
cv2.waitKey(0)
"""
Loading…
Cancel
Save