Gaming World Forums

Creativity => Game Design & Demos => Topic started by: goldenratio on August 12, 2009, 12:50:19 am

Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 12:50:19 am
Dung - The Dungeon Generator
Collect the treasure and escape the dungeon, if you can!


So here's a thing I did in Python using pygame. The core is a random dungeon generator, which at this point is very simple, but that is the piece I actually set out to write, and the "game" I built around it is really only there so there's something to DO with the dungeon. I find it briefly yet strangely enthralling.

This is my first test using py2exe, and it was a bitch to finally get working, but it will run on my computer. Hopefully it will work for you, but if it doesn't let me know so I can fiddle until it finally gets right. I had to include a bunch of DLLs for pygame, which together is only 1mb, but I also had to include all my resources. I can't get the damn thing to compile it ALL into the EXE. If anybody knows, help me out.


So anyways, I was just hoping you could maybe play it for a bit, and assuming it works check out the random dungeons. It's not very random at this point, and you may be able to see what I'm doing, but I plan on improving it, hopefully with some input.

If anybody is interested in my methods or wants to see source code, let me know. I'm not trying to keep it secret.

(http://pub.gamingw.net/24779/Dung2.png)


Download Link (http://sharebee.com/280935f7)
Direct Mirror - Thanks Tomato! (http://templeofskulls.tomatopia.com/game/dung%20-%20the%20dungeon%20generator.zip)
Download Source (http://sharebee.com/65c381c6) - requires Python 2.6 and pygame

download size: 6.5mb

sorry its the only place i know to upload stuff. I can upload it anywhere if you want me to.
Title: Dung - The Dungeon Generator
Post by: Sludgelord on August 12, 2009, 12:59:31 am
i will be checking this out in a little bit pal. i like the name.
Title: Dung - The Dungeon Generator
Post by: Immakinganaccountk on August 12, 2009, 01:10:26 am
Are you the first of about 4 people to finish this, or just the first to release it? I thought there was a race or something going on. :welp:
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 01:11:56 am
what are you talking about? i just made this for fun.
Title: Dung - The Dungeon Generator
Post by: unusualgamer on August 12, 2009, 01:19:31 am
cool I downloaded this, will try it soon.
Title: Dung - The Dungeon Generator
Post by: Mince Wobley on August 12, 2009, 01:29:58 am
It works can you post the source? I'm curious about the algorithm can you describe what it does before posting the sauce?
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 01:43:51 am
Sure.

Basically I call the dungeon generator with the rows, columns, rooms ("features"), and "specials". I create a list of lists of ints, all 0. The values I use are:

0: can't walk
1: can walk
2: start
3: exit
4: "special" (item)

So I have a grid of values, and I just create the specified number of "features" (which are random rectangles, between 2 and 6 units wide/tall). As I am creating features, I keep track of which features are the farthest apart. This is where I'll place the start and end points.

After I create all the features, I go through each one like a linked list, and conect each one together (using a very simple "go x cells over, and y cells up/down (actually this is random, and will either go x/y or y/x, just to give it some randomness)")

Then I place the start and end points (in the farthest apart rooms, just so you dont randomly spawn right next to the exit. although this wouldn't be so bad, since you have to collect the treasure first. I did this part before I had items at all.)

At the very end I just pick random open spaces, and make them items.

This is just the dungeon generator part (I tried to make it reusable so this class only generates the grid of numbers). My "World" class then actually creates all the "game" related stuff.

http://snipplr.com/view/18189/random-dungeon-generator/
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 12, 2009, 02:08:50 am
This looks like DUNG compared to my generator. nice try..... why dont  u just let the pros do it kid?
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 02:10:44 am
i dont care about the naysayers. i think my game is good and thats all that matters so you can take it somewhere else :P
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 12, 2009, 02:15:29 am
in all seriousness, your source code is 3000 times easier to understand than mine. so good job dude! if pygame is faster than ika, i might switch over to it.
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 02:21:25 am
let me see yours!

this is like the 6th iteration. Early on, I was trying to just move forward in random directions, but it was way complex and didn't work at all. I made it simpler and simpler each time, and this is my end result. I tried to be as "pythonic" as I knew how, and in the spirit of python tried to do everything as simple as possible.
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 12, 2009, 02:22:26 am
http://templeofskulls.tomatopia.com/game/Sandbox%202.7z

and here's a mirror for your game: http://templeofskulls.tomatopia.com/game/dung%20-%20the%20dungeon%20generator.zip.

Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 03:52:14 am
i see your section for "check to make sure rooms don't overlap" code isn't there, just like mine :)
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 12, 2009, 04:34:10 am
hmm?? uh, it should be there! I just forget to update the comments.

def abletogen(self,ch_sx, ch_sy, ch_w, ch_h):
    check = 1
    global points
    for check_w in range(ch_w):
    for check_h in range(ch_h):
    if self.map[ch_sx+check_w][ch_sy+check_h] > 0:
    check = 0
    for check_w in range(ch_w):
    for check_h in range(ch_h):
    if self.map[ch_sx-check_w][ch_sy-check_h] > 0:
    check = 0
        return check
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 04:49:12 am
i must have been looking in another place. nevermind.

Also here is the full source for my game. You need python 2.6 and pygame. I've never used ika but i've looked at it quite a bit. ika basically just has all the boilerplate rendering/update loop/common stuff for you. Not sure if its faster, as I would imagine the ika code should be pretty optimized and not get in the way, but you do get more control with pygame, even if you have to set up all that rendering shit (although as you can see from my 'dung.py' (the main script) there's not much in the way of rendering/boilerplate code.

Run dung.py like

python dung.py

http://sharebee.com/65c381c6
Title: Dung - The Dungeon Generator
Post by: Ciox on August 12, 2009, 05:25:47 am
I love random generation and this is pretty good, the smooth movement is so soothing..
You might want to add something so that you don't have to perfectly dock with corridors, so if you're a bit misaligned it nudges you in and you can go down the corridor.
Can't think of anything else since there isn't much to do.


I tried to run yours Tomato but it asked for like a zillion extra dlls and I kinda stopped when I couldn't find python25.dll on the net.
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 05:27:59 am
Cool thanks man. I made the collision boxes for the player smaller when testing with walls, and  larger when testing with treasure. Maybe I need to make it a few more pixels smaller.
Title: Dung - The Dungeon Generator
Post by: unusualgamer on August 12, 2009, 07:33:38 am
I noticed that too; when I approach the 'treasure' I didn't have to be exactly near it to grab it, but for passages I had to be exactly lined up to get through them. Not really a big deal.

I liked the simplicity of it. The random generator worked great. Movement was as smooth as butter.

Overall excellent work.
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 12, 2009, 08:43:45 pm
Yeah, the movement was really smooth. i might have to put something like that into my game.
Title: Dung - The Dungeon Generator
Post by: unusualgamer on August 12, 2009, 08:55:12 pm
Alright, so I found a gripe.

The text gets in the way of the 'treasures' and 'exits' sometimes. It's not really a big deal, but if I were you I would make the instructions text at the bottom disappear over time, and probably put the alert text at the top of the screen in its own HUD.
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 12, 2009, 09:30:34 pm
Yeah that's legitimate. I should fix that. That's probably next, dividing up the screen into a "map" area and a "hud" or whatever. Or at least leave a margin or something and make the text show up in there.

Also fyi if you press space it will make a new map.
Title: Dung - The Dungeon Generator
Post by: Biggles on August 13, 2009, 04:45:43 am
Thanks for posting the source version. It's nice to see a game posted here that I can run on Linux. It's always really disappointing when someone someone posts something I want to try and it's windows-only. Your code is also really legible, especially compared to some other pygame projects I've read in the past.

I also have a suggestion to improve the fluidity of the movement code: the "requires perfect alignment when going through gaps" seems to have been solved in a couple of different ways (that I have noticed) in commercial 2D games. One way is by using tile based movement, but tile based movement sucks unless you're making a puzzler or RPG and sometimes it even sucks then. The way I like better for pixel-based movement is that the game detects if a player has just missed a gap and sort of pulls them sideways at about one pixel per frame until the hitbox is aligned so that they can go through. It tends to trigger when about half your hitbox or so is over the gap, which sort of looks natural. You can find it in a lot of the 2D Zeldas (http://www.youtube.com/watch?v=nD2r6RSNPOE), and it's easy to imagine that they would feel much clunkier without this minor detail. For example, near the start of that video where the player rolls into the corner slightly, if the game did not autocorrect his movement he would have just stopped awkwardly because the game doesn't allow direction change / influence during a roll.

I was actually going to suggest code to implement this in 'World.py' (particularly as a proof of concept to myself that this really does improve the way movement feels) but to tell the truth I'm stuck as to how gap detection would best be done. On the one hand, you could write a function that just iterates all walls and checks if there's an adjacent wall to the one you're colliding with in the direction you're moving in,  and then returns whether it's above, below, left or right of you, or whether there isn't one. This seems kind of wasteful, though. It requires an extra O(n) on the number of walls every time you collide, and the code hardly sounds elegant. On the other, you could have each wall store the walls above, below, left and right of it as a kind of 'linked grid', but this seems like unnecessary bulk added to the walls class.

So yeah, sorry for providing you with a big long description of the suggestion for such a minor detail and then not helping at all on the implementation. I thought it might be useful to post anyway because I think a lot of people don't know about this whole auto-cornering thing and if my theory about how it works is correct then it might help more than one game be less clunky.
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 13, 2009, 05:02:46 am
Well by decreasing the collision rectangle for the player when checking for walls, it should let you "start entering" the gap, and the type of collision detection I do actually does nudge the player back outside the wall, but I think my code doesn't do the "move" correctly. Perhaps decreasing the size of that rectangle even more (I do it like 2-3 pixels right?) and double-checking the "move back" stuff would make it work.
Title: Dung - The Dungeon Generator
Post by: Biggles on August 13, 2009, 05:19:31 am
The "move back" stuff seemed to be working fine when I played the game, but that's not going to draw them into the gap, is it? Also wouldn't using a much much smaller rect in colliding with walls just result in a weird looking overlap? Maybe I'm understanding you wrong.
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 13, 2009, 05:40:48 am
yeah you're probably right. I have no idea how to implement any of the stuff you said though so I'll just be thinking about it. If you have any ideas let me know.

The only way I can imagine it working, is to check if less than a certain % or number of pixels is touching the wall, and if the direction you are moving has an open space you CAN move it, then move you there. It's seems fairly simple, but I can't think of a good algorithm that wouldn't be hugely wasteful. I mean I guess at MOST i'd need to check 8 tiles (the tiles directly around the player), and really only 3 (the 3 in the direction you are moving), so maybe i'll try some of this. It would need to be smooth, is the only thing, so I'd have to actually animate diagonally and stuff, I think. Hmm...

Also the next thing I was thinking of implementing was enemies, with some A* pathfinding.
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 13, 2009, 05:56:26 am
do you know of any good websites that describe A* pathfinding in detail?
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 13, 2009, 06:03:26 am
http://www.policyalmanac.org/games/aStarTutorial.htm

This one explains it very well. Here's part two (havent read this yet, just found it now): http://www.policyalmanac.org/games/twoTiered.htm

Also if you're making games with python, have you read Beginning Game Development with Python and Pygame (http://www.apress.com/book/view/9781590598726)? PM if you want a copy, its really really good, has awesome examples with all sorts of stuff. It doesn't seem to go over gravity and stuff like that, which sucks, but it gives very good intros on Vectors and state machines and things. It's a really good book, IMO.
Title: Dung - The Dungeon Generator
Post by: Mince Wobley on August 13, 2009, 06:11:01 pm
I once coded A* from the wikipedia article on it because it was more abstract, I always saw those A* tutorials where they show those tiled maps and I never understood how to implement them on anything other than tiles
Title: Dung - The Dungeon Generator
Post by: Dale Gobbler on August 13, 2009, 07:22:11 pm
I probably wouldn't use it, but it looks like a well constructed, functional pile of crap. :fogetnaughty:
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 13, 2009, 08:19:24 pm
Mince, to use an A*-like algorithm without tiles, you would use "nodes" instead. The nodes could be like waypoints you place on a map, or calculated like tiles, but the nodes themselves (which are just points) are like the "tiles" you see in the tutorials.
Title: Dung - The Dungeon Generator
Post by: Mince Wobley on August 13, 2009, 09:04:11 pm
Mince, to use an A*-like algorithm without tiles, you would use "nodes" instead. The nodes could be like waypoints you place on a map, or calculated like tiles, but the nodes themselves (which are just points) are like the "tiles" you see in the tutorials.

I know, I already did that I just didn't understand from reading the tile based a* tutorials that the tiles were in fact the "nodes" due to poor attention span

Title: Dung - The Dungeon Generator
Post by: goldenratio on August 14, 2009, 01:01:32 am
jeez louise, thanks a lot aztec.
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 14, 2009, 04:41:03 am
if you want, I can post my A* code here that I just got functioning. it probably has a few bugs.
Title: Dung - The Dungeon Generator
Post by: goldenratio on August 14, 2009, 05:15:50 am
hell yes bro
Title: Dung - The Dungeon Generator
Post by: the bloddy ghost on August 14, 2009, 06:17:12 am
def pathfind(startx=0,starty=0,endx=4,endy=0):
notdone = 1
crashguard = 0
#Add the starting square (or node) to the open list.
openlist = [[startx,starty, 0, (abs(startx - endx * 10))+(abs(starty - endy*10))]]
closedlist = []
inlist = 0
while notdone:
lowestf = openlist[0]
entity.DBmsg("Starting Pathchecking loop...")
#Repeat the following:
for f in openlist:
#a) Look for the lowest F cost square on the open list. We refer to this as the current square.
if f[2]+f[3] < lowestf[2]+lowestf[3]:
lowestf = f
#b) Switch it to the closed list.
closedlist.append(lowestf)
entity.DBmsg("Added:" + str(lowestf[0]) +"," + str(lowestf[1]) + " to path list.")
if lowestf[0] == endx and lowestf[1] == endy:
notdone = 0
for f in openlist:
if f == lowestf:
openlist.remove(f)
pass
for x in range (0,3):
for y in range(0,3):
#If it is not walkable or if it is on the closed list, ignore it. Otherwise do the following.
if game.levels[game.gv_currentdungeon].map[lowestf[0]-1+x][lowestf[1]-1+y] == 1:
entity.DBmsg("Can't add that square.")
pass
else:
if x == 0 and y == 0:
listcheck = [lowestf[0]-1+x,lowestf[1]-1+y,14,(abs(lowestf[0]-1+x - endx * 10))+(abs(lowestf[1]-1+y- endy*10))]
else:
listcheck = [lowestf[0]-1+x,lowestf[1]-1+y,10,(abs(lowestf[0]-1+x - endx * 10))+(abs(lowestf[1]-1+y- endy*10))]
for f in openlist:
if inlist == 0:
#If it is on the open list already, check to see if this path to that square is better, using G cost as the measure.
                                                        #A lower G cost means that this is a better path. If so, change the parent of the square to the current square,
                                                        #and recalculate the G and F scores of the square. If you are keeping your open list sorted by F score, you may need to resort the list to account for   
                                                        #the change.
if f[0] == listcheck[0] and f[1] == listcheck[1]:
inlist = 1
if listcheck[2] < f[2]:
openlist.remove(f)
openlist.append(listcheck)
else:
inlist = 0
openlist.append(listcheck)
crashguard += 1
if crashguard == 1000:
return closedlist
return closedlist
it's very buggy. any ideas on how to fix it?