Gaming Your Way

May contain nuts.

Dungeons: Explained better

A bit of a repeat post. Nothing from us for ages, and then when it arrives it's just a rehash. Ages back I did try and explain how we make the dungeons in Knight'sQuest ( FB link ), but using test data images along with poor writing didn't explain it too well I don't think.

Ok, so we have at the basis Olli's dungeon generator code. This creates an array of objects describing a room / corridor. Each room is made up of blocks and blocks are made up of 4x4 tiles. The rooms are made up of a variable number of blocks, so we can have small tight rooms or bigger expansive areas.

When plotting a dungeon ( A generic term, it covers the caves and the new forest ) we look through each room which starts its life as just a collection of 4 digit numbers which are stored in a clock wise fashion ( North, East, South and West ) and each tell us if there's a wall / door / nothing.
For example, if we get the code 0111 that means there are walls to the north, and nothing in any of the other directions ( Little weird 1 meaning an empty space, to be honest I couldn't face refactoring Olli's code ).

Due to the large number of combinations, using a switch / if statement was a non starter, I'd still be typing it now, so we used this cheeky bit of code,

            var directionsAsString:String;             if(location=="caves"){                 directionsAsString="caves_"+northWallValue+eastWallValue+
southWallValue+westWallValue;             } else {                 if(location=="dungeon"){                     directionsAsString="dung_"+northWallValue+eastWallValue+
southWallValue+westWallValue;                 } else {                     if(location=="forest"){                         directionsAsString="forest_"+northWallValue+eastWallValue
+southWallValue+westWallValue;                     }                 }                     }                          try {                 var functionCall:Function=this[directionsAsString];                 functionCall();             }             catch (e:Error){ Debug.trace(directionsAsString,2);                 if(location=="caves"){                     caves_1111();                 } else {                     if(location=="dungeon"){                         dung_1111();                     } else {                         if(location=="forest"){                             forest_1111();                         }                     }                 }             }

Basically we just turn the value into a function call. The try / catch is there in case I've missed one of the possible combinations ( And the trace is so I can find out which and fix it ). Using our current example value from above, and we're in the forest this time, we'd call the function

private function forest_0111():void{

Which is a million times easier than any sort of conditional.

Right we now know what block we need to plot ( Take it as read we know the x/y position of it, this isn't the most fun post in the world as it is without me going into that depth ), how do we store the blocks themselves ?

KQ_darkForest.jpg


In the IDE we have block movieclips, like you can see above. Inside those blocks we have a floorMC and then the tiles. For the floor we just use bitmap draw() to grab it and turn it into a bitmap, and then burn that into the master ground bitmap ( All the floors in the game are just one huge bitmap, so no depth sorting or messing around, it's just a flat bitmap we scroll ).
The beauty of this approach is that the floors are in effect art style, we can drop any image on any pixel position, use blendmodes / alpha / scaling / anything really and because we're just burning it into the ground bitmap all this extra stuff is basically free.

That's the floor covered, next the tiles. Each tile in a block is just a movieclip, with an instance name. See that campfire on the top left block ? That's got the instance name "forest_088", and we just store that in an array with a reference to the bitmap of that image ( We're using the blitter for everything, which means bitmaps ). When plotting a block we loop through all the tile mc's in the block, find out the reference to it's bitmap and create a Bob ( Blitter OBject, ie a sprite ) for it.
In terms of layout, we don't have to be really anal, none of these tiles are pixel perfect aligned, that would be soul destroying, so the plotter rounds things down and most of the time gets it right.
One other slight bit of weirdness before we move on, each instance of a certain tile has to have the same name. Going back to the top left block, notice all the trees are the same ? They are all called "forest_008". Normally we'd never use the same instance name, as that's mental and wrong, but all we're doing is looping through each mc in the block, getting it's x,y position relative to the blocks origin, and then it's .name so we can look up the bitmap reference.

Not easy going I know, sorry. We're nearly there.

Notice we've got 4 blocks all with a north facing wall. To try and make the dungeons look as good as possible we make as many variations of each block as we can face. Before we actually plot them, we pick one at random ( Again, another array, just listing each possible block for each possible combination ).

If you've got this far then well done. Hopefully it explains things better than before.

Squize.

Comments (7) -

  • nGFX

    2/13/2011 7:25:16 PM |

    Just because you don't see the point using '0' for an 'empty' side, it doesn't meanthere isn't a reason for it. Basically it's for easier testing, because a door (2) can be seen as blocking wall it's easier to check for !=0 if you want to know that you can't go there.

    just my 2 cents.

    :-)

    <olli/>

  • Squize

    2/13/2011 7:26:34 PM |

    Ah, wondered what the reason for that was :)

  • Rasmus Wriedt Larsen

    2/14/2011 12:25:33 AM |

    For the part about instance names, instead you could do this for each child:

    Object ( child ) . constructor;

    this would give you a reference to the class of the child, which you could then you to find its' index.

    This could be a pain to implement now, but boy are you going to be angry when you find out that 50% of the forest_008 needs to be called forest_009 :D

  • Squize

    2/15/2011 5:41:58 PM |

    That's a good point. At present the tile mc's aren't even exported, it's just the instance names and positions we care about.

    In theory each block could just have been laid out in an 2D array, but from a design point of view the IDE was a million times better.

    Thanks for the tip mate, if I ever do another RPG... ( You'd have to put a gun to my mums head :) ).

  • Bryson

    3/3/2011 4:13:57 AM |

    I want to say you're insane for laying everything out in the IDE by hand but it's probably insane no matter how you'd go about creating a game on this scale. Great stuff!

    If you had to do something like this again would you still go the IDE route? Or make a level editor?

  • Squize

    3/3/2011 9:54:42 AM |

    Hi mate.

    You can only imagine how painful doing all the blocks was :) Getting all the possible combinations down did take a while, with the only way to really test things was by playing through lots and lots of random levels to see if we got an error.

    On the plus side, the positioning of each tile within in a block didn't have to be pixel perfect, so long as it wasn't miles out the code would get it right, and once all the blocks were in Lux [ On the cave levels ] could go in there and make as many as he wanted and fine tune things up. Being able to have "Art based" floors helped with the variety a lot, something we wouldn't have been able to do without an editor ( The screen shot examples don't really show this as for the dark forest we didn't want a really busy floor ).
    Also by using the IDE there's no learning curve for the designer, there's no messing around adding features and bug fixing for me ( If we were using a home brew editor ), in the case of the floors we get to use filters / tints etc. if wanted, we can flip tiles around etc.

    I'd say the two additional areas took around 2*8 hour days each, including doing the animation, which isn't too bad for then an infinite number of levels, and I don't think any of the 3 levels uses more than 60 tiles, which is really next to nothing.

    Hope that all makes sense :)

  • Bryson

    3/15/2011 5:45:26 PM |

    Thanks for clarifying. I sometimes battle with whether I should build out a level editor or just leverage the capabilities of the IDE. It's good to have your perspective of what the benefits were for this project. It actually helps me feel less crazy for doing similar things myself. haha

Comments are closed