Loaded the mapgen class into a pygame testbed |
I know this is a crappy screenshot, but you can see that there are several rooms (the black rectangles) and hall-objects that connect them. Ignore the crappy images I used for the rooms and player objects. I know they suck, but I've been using them as my standard test images for a while now.
Currently the room generator chooses from a number of pre-loaded images and scales the image to fit the random size. I'm thinking I may change it to tile a floor pattern on the room after a size is chosen. This way I don't end up with floors that are clearly the same image, just stretched to fit. Either that, or just use the same floors and have the room generators just draw random carpets or mats or something to draw attention from the stretched image underneath...
I also want to place some generic walls on each room/hall then add random pictures, posters and windows.
For now though, you just import the class, and run genMaps() and it returns a list (or array if you prefer) of these room/hall objects. You can then use the pygame rectangle objects for collisions and the pygame image (surface) objects to draw them to another surface.
Here's the source for this class file:
Click here to expand Source
import random, pygame
class RoomObj:
def update(self,anchorpoint):
self.rect.left = self.xoffset + anchorpoint[0]
self.rect.top = self.yoffset + anchorpoint[1]
class Room(RoomObj):
def __init__(self, imageset, direction=0, room_rect=None):
#RoomObj.__init__(self)
self.direction = random.randint(1,4) #up, down, left, right
self.size = (random.randint(400,600),random.randint(500,700))
self.image = pygame.Surface(self.size)
pygame.transform.scale(random.choice(imageset), self.size, self.image)
self.rect = self.image.get_rect()
if direction==0:
self.rect.top = 0
self.rect.left = 0
if direction==1:
if self.direction == 2:
self.direction = 1
self.rect.bottom = room_rect.top
self.rect.left = room_rect.left-(self.size[0]/2)
if direction==2:
if self.direction == 1:
self.direction = 2
self.rect.top = room_rect.bottom
self.rect.left = room_rect.left-(self.size[0]/2)
if direction==3:
if self.direction == 4:
self.direction = 3
self.rect.top = room_rect.top-(self.size[1]/2)
self.rect.right = room_rect.left
if direction==4:
if self.direction == 3:
self.direction = 4
self.rect.top = room_rect.top-(self.size[1]/2)
self.rect.left = room_rect.right
self.xoffset = self.rect.left
self.yoffset = self.rect.top
class Hall(RoomObj):
def __init__(self, direction, room_rect, imageset):
#RoomObj.__init__(self)
self.size = (80,random.randint(100,300))
self.image = pygame.Surface(self.size)
tmpimage = random.choice(imageset)
if direction==1:
self.image = pygame.transform.scale(tmpimage, self.size, self.image)
self.rect = self.image.get_rect()
self.rect.bottom = room_rect.top
self.rect.left = random.randint(room_rect.left, room_rect.right-80)
self.direction=1
if direction==2:
self.image = pygame.transform.scale(tmpimage, self.size, self.image)
self.rect = self.image.get_rect()
self.rect.top = room_rect.bottom
self.rect.left = random.randint(room_rect.left, room_rect.right-80)
self.direction=2
if direction==3:
self.size = (self.size[1],self.size[0])
self.image = pygame.Surface(self.size)
self.image = pygame.transform.rotate(tmpimage, 90)
#print self.size
#print self.image.get_size()
self.image = pygame.transform.scale(tmpimage, self.image.get_size(), self.image)
self.rect = self.image.get_rect()
self.rect.top = random.randint(room_rect.top, room_rect.bottom-80)
self.rect.right = room_rect.left
self.direction=3
if direction==4:
self.size = (self.size[1],self.size[0])
self.image = pygame.Surface(self.size)
self.image = pygame.transform.rotate(tmpimage, 90)
self.image = pygame.transform.scale(tmpimage, self.image.get_size(), self.image)
self.rect = self.image.get_rect()
self.rect.top = random.randint(room_rect.top, room_rect.bottom-80)
self.rect.left = room_rect.right
self.direction=4
self.xoffset = self.rect.left
self.yoffset = self.rect.top
def genMap(size,roomimages,hallimages):
"""
takes 3 perameters: size (string), roomimages (array of pygame images/surfaces),
and hallimages (also an array of pygame images)
size should be small, medium or large
the two arrays should use pygame.image.load() objects or pygame.Surface objects
e.g. [pygame.image.load("file1.png").convert_alpha(), pygame.image.load("file2.jpg)]
returns an array containing room and hall objects.
each room or hall can be moved through the use of an anchor point variable.
e.g. mapobjects[0].update(anchorpoint) where anchorpoint is the (x, y) offset
"""
numofrooms=0
if size=='small':
numofrooms = random.randint(3,5)
if size=='medium':
numofrooms = random.randint(5,8)
rooms = []
map = []
for i in range(numofrooms):
if i == 0:
tmproom = Room(roomimages)
map.append(tmproom)
tmphall = Hall(tmproom.direction, tmproom.rect, hallimages)
map.append(tmphall)
else:
if i < len(range(numofrooms))-1:
tmproom = Room(roomimages, tmphall.direction, tmphall.rect)
map.append(tmproom)
tmphall=Hall(tmproom.direction, tmproom.rect, hallimages)
map.append(tmphall)
else:
map.append(Room(roomimages, tmphall.direction, tmphall.rect))
return map
*Edited - 6-21-2013* I decided to go through the class file and make a few minor updates. I added some checking to see if there was an existing object where the new room was going to be placed. I also changed the logic a bit in the loop that created the Rooms/Halls. I also went through and commented it all. (Except the Room subclass; I figured it was close enough to the Hall, I didn't need to comment both)
In any case, here's the cleaned up class file:
Click here to expand the cleaned up Source
import random, pygame
class RoomObj:
def __init__(self, wallimgset):
if self.type == 'room':
#create walls for a room
pass
if self.type == 'hall':
#create walls for a room
pass
def update(self,anchorpoint):
self.rect.left = self.xoffset + anchorpoint[0]
self.rect.top = self.yoffset + anchorpoint[1]
class Room(RoomObj):
def __init__(self, imageset, direction=0, room_rect=None, wallimgset=[]):
#main room rectangle
self.type = 'room'
self.direction = random.randint(1,4) #up, down, left, right
self.size = (random.randint(400,600),random.randint(500,700))
self.image = pygame.Surface(self.size)
pygame.transform.scale(random.choice(imageset), self.size, self.image)
self.rect = self.image.get_rect()
if direction==0:
self.rect.top = 0
self.rect.left = 0
if direction==1:
if self.direction == 2:
self.direction = 1
self.rect.bottom = room_rect.top
self.rect.left = room_rect.left-(self.size[0]/2)
if direction==2:
if self.direction == 1:
self.direction = 2
self.rect.top = room_rect.bottom
self.rect.left = room_rect.left-(self.size[0]/2)
if direction==3:
if self.direction == 4:
self.direction = 3
self.rect.top = room_rect.top-(self.size[1]/2)
self.rect.right = room_rect.left
if direction==4:
if self.direction == 3:
self.direction = 4
self.rect.top = room_rect.top-(self.size[1]/2)
self.rect.left = room_rect.right
self.xoffset = self.rect.left
self.yoffset = self.rect.top
RoomObj.__init__(self,wallimgset)
class Hall(RoomObj):
#initialize our hall object
def __init__(self, direction, room_rect, imageset, wallimgset=[]):
self.type = 'hall'
#size may want to be changed to be relative to screen size
self.size = (80,random.randint(100,300))
#will be surface that is drawn to screen
self.image = pygame.Surface(self.size)
#will be drawn to self.image surface
tmpimage = random.choice(imageset)
#hall will be facing up and down
if direction==1:
self.image = pygame.transform.scale(tmpimage, self.size, self.image)
self.rect = self.image.get_rect()
self.rect.bottom = room_rect.top
self.rect.left = random.randint(room_rect.left, room_rect.right-80)
self.direction=1
#hall will be up and down
if direction==2:
self.image = pygame.transform.scale(tmpimage, self.size, self.image)
self.rect = self.image.get_rect()
self.rect.top = room_rect.bottom
self.rect.left = random.randint(room_rect.left, room_rect.right-80)
self.direction=2
#hall will be left to right
if direction==3:
self.size = (self.size[1],self.size[0])
self.image = pygame.Surface(self.size)
self.image = pygame.transform.rotate(tmpimage, 90)
self.image = pygame.transform.scale(tmpimage, self.image.get_size(), self.image)
self.rect = self.image.get_rect()
self.rect.top = random.randint(room_rect.top, room_rect.bottom-80)
self.rect.right = room_rect.left
self.direction=3
#hall will be left to right
if direction==4:
self.size = (self.size[1],self.size[0])
self.image = pygame.Surface(self.size)
self.image = pygame.transform.rotate(tmpimage, 90)
self.image = pygame.transform.scale(tmpimage, self.image.get_size(), self.image)
self.rect = self.image.get_rect()
self.rect.top = random.randint(room_rect.top, room_rect.bottom-80)
self.rect.left = room_rect.right
self.direction=4
#set offset to use with the update function
self.xoffset = self.rect.left
self.yoffset = self.rect.top
#init the parent class to create the walls and draw the floors
RoomObj.__init__(self, wallimgset)
def checkForExisting(room, maplist):
for i in maplist:
if room.rect.contains(i.rect):
return True
return False
def genMap(size,roomimages,hallimages):
"""
takes 3 perameters: size (string), roomimages (array of pygame images/surfaces),
and hallimages (also an array of pygame images)
size should be small, medium or large
the two arrays should use pygame.image.load() objects or pygame.Surface objects
e.g. [pygame.image.load("file1.png").convert_alpha(), pygame.image.load("file2.jpg)]
returns an array containing room and hall objects.
each room or hall can be moved through the use of an anchor point variable.
e.g. mapobjects[0].update(anchorpoint) where anchorpoint is the (x, y) offset
"""
#num of rooms will be number of nodes to create
numofrooms=0
if size=='small':
numofrooms = random.randint(3,5)
if size=='medium':
numofrooms = random.randint(5,8)
#add a few to account for joining hall nodes
numofrooms = numofrooms+(numofrooms-1)
rooms = []
map = []
#while map array length is less than total number of desired nodes...
while len(map) < numofrooms:
#first create a room and a hall
if len(map)==0:
tmproom = Room(roomimages)
map.append(tmproom)
tmphall = Hall(tmproom.direction, tmproom.rect, hallimages)
map.append(tmphall)
#create all other nodes
else:
# if there are at least 2 spots left on the list, create a room, then a hall
if len(map) < numofrooms-2:
tmproom = Room(roomimages, tmphall.direction, tmphall.rect)
#loop several times to ensure the new room isn't put on top of an old one
#counter is to ensure we don't end up with an endless loop
counter = 0
while checkForExisting(tmproom, map):
tmproom = Room(roomimages, tmphall.direction, tmphall.rect)
counter+=1
#we tried 10 times and couldn't place the room, knock off the last
#hall and room, and try again
if counter >10:
map = map[:-2]
map.append(tmproom)
tmphall=Hall(tmproom.direction, tmproom.rect, hallimages)
map.append(tmphall)
#only one spot left on our list? create a room
if len(map) == numofrooms-1:
tmproom = Room(roomimages, tmphall.direction, tmphall.rect)
counter=0
while checkForExisting(tmproom, map):
tmproom = Room(roomimages, tmphall.direction, tmphall.rect)
counter+=1
if counter >10:
map = map[:-2]
#map.append(Room(roomimages, tmphall.direction, tmphall.rect))
map.append(tmproom)
return map