dungeon / generator.py
Jessedbrown's picture
generate dungeon
7c3a188
Raw History Blame Contribute Delete
4.72 kB
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line, Rectangle, Bezier
from kivy.properties import NumericProperty, ObjectProperty, ListProperty
from kivy.uix.label import Label
from kivy.vector import Vector
from kivy.logger import Logger
from kivy.clock import Clock
from room import Room
from hallway import Hallway
from random import randint
from scipy.spatial import Delaunay
from collections import deque, defaultdict
from itertools import combinations
from gridwidget import GridWidget
class DungeonGenerator(Widget):
n_rooms = NumericProperty(40)
rooms = ListProperty([])
hallways = ListProperty([])
def __init__(self, rooms=None, **kwargs):
super(DungeonGenerator, self).__init__(**kwargs)
self.n_rooms = (rooms or self.n_rooms)
def generate_rooms(self, n_rooms=None, clear=True, minSize=2, maxSize=10):
'''
'''
n_rooms = (n_rooms or self.n_rooms)
if clear:
self.canvas.clear()
self.clear_widgets()
self.rooms = []
self.edges = []
self.hallways = []
for n in range(n_rooms):
r = Room(text=f'{n}', minSize=minSize, maxSize=maxSize)
self.rooms.append(r)
self.add_widget(r)
self.move_rooms(self.center)
def spread_out_rooms(self, dt):
'''
'''
if self.rooms_in_motion():
self.collide_rooms()
self.move_rooms()
return False
return True
def identify_rooms(self, top=20, clear=False):
'''
'''
if len(self.rooms) <= top:
return True
self.rooms = sorted(self.rooms,
key=lambda v:v.area,
reverse=True)
for i,room in enumerate(self.rooms):
if i < top:
room.background = [0,1,0,0.5]
room.foreground = [0,1,0,1]
else:
room.background = [1,0,0,0.5]
room.foreground = [1,0,0,1]
if clear:
self.clear_widgets(self.rooms[top:])
self.rooms = self.rooms[:top]
return True
def align_rooms_to_grid(self, grid=None):
'''
'''
for room in self.rooms:
room.align_to_grid(grid)
def rooms_in_motion(self):
'''
'''
for room in self.rooms:
if room.v_x or room.v_y:
return True
return False
def collide_rooms(self):
'''
'''
for room in self.rooms:
room.collide_widgets(self.rooms)
def move_rooms(self, pos=None):
'''
'''
if pos:
for room in self.rooms:
room.pos = pos
return
for room in self.rooms:
room.move(self.width, self.height)
def centroid_of_rooms(self):
'''
'''
Cx,Cy = 0,0
n = len(self.rooms)
for room in self.rooms:
Cx += room.x
Cy += room.y
return (Cx / n, Cy / n)
def center_rooms(self, pos=None):
'''
'''
pos = (pos or self.center)
self.align_rooms_to_grid()
c = self.centroid_of_rooms()
dx = abs(c[0] - pos[0])
dy = abs(c[1] - pos[1])
for room in self.rooms:
room.pos = Vector(room.pos) + (dx,dy)
def build_hallways(self):
'''
'''
tris = Delaunay([room.center for room in self.rooms])
for t in tris.simplices:
for a,b in combinations([self.rooms[i] for i in t], 2):
a.friend(b)
for room in self.rooms:
neighbors = list(room.neighbors) # avoid mutating room.neighbors
for n in neighbors:
if room.weight <= 3:
break
if n.weight > 1:
room.unfriend(n)
Logger.info(f'Prune: room {room.text} weight {len(neighbors)} -> {room.weight}')
Logger.info(f'Hallways:')
hallways = {}
for room in self.rooms:
for neighbor in room.neighbors:
h = Hallway(room, neighbor)
try:
hallways[h.key]
del(h)
except KeyError:
hallways[h.key] = h
self.hallways = list(hallways.values())
base = len(self.children)
for i, h in enumerate(self.hallways):
self.add_widget(h, index=base+i)