How hard is it to make an isometric random map?

  • This is something I've been thinking about for a while since I'm getting started on making the actual levels for my game which is an isometric turn-based rpg.

    There are two ways I could do it. One is to create the map by hand, placing the sprites where I want them. It would just be a matter of making the sprites and marking off where I want the solid borders to be for pathfinding. Nothing too difficult there. The main advantage here is complete control over the visual elements so I could make a better looking game. The downside is that the level will always be the same, save for random enemy placement and difficulty.

    The other option is to randomly generate a map. The advantage to this would be having a different layout each time. The downsides are that it's harder to make it look nice. I can't place "filler" sprites to cover weak areas or to add in detail as easily since they would need to be placed in the proper location. I also have to make sure the map "works" and is still interesting. The major issue I've had is placing structures such as a long wall, a river, a long cliff, anything that is not just one sprite but a group of sprites that need to line up or make sense.

    Here are a couple different examples.

    The first is from Age of Empires II, and the second is from Baldur's Gate II.

    I can adapt the game to work with either type of map. I would lean more towards the Baldur's Gate style map since this is an RPG after all.

    The AoE map is probably easier to make. It is more open and would only need correct sprite placement so that it looks nice. If I add water, I would have to worry about islands I can't reach or whatnot. If I add trees, I would want them in groups preferably but not blocking paths either. I would have to create some sprites to indicate shorelines for each side and some corner pieces and place them correctly, which seems like it would be tricky.

    The Baldur's Gate style maps rely more on paths and rooms. The biggest challenge is how to make the walls have proper corner pieces, be the proper thickness (as you can see in the picture some rooms are very close together, and others have more space around them.) Even if I set up some sort of code to randomly place rooms and hallways, I would still need the textures/sprites to be in the correct place. A wall needs to have an actual end to it and fit in with the corner of the next wall.

    All of this is easy with manual placement. I just create some sprites (walls, rocks, etc.) and place them where I want them until the level is built.

    I've messed with arrays a little bit, and looked at some random map generators here. I really can't see any way to make a functional world that's both random and isometric and actually works. Placing isometric objects like a tree is not hard, and I could make the ground tiles diagonal or whatever.

    But getting walls built around paths and things like that is just really confusing, assuming I could build an isometric hallway to begin with. Has anyone had any success with anything like this?

  • Forget about isometric for a moment and look at doing it only in 2d. Isometric can be added later easily enough with the only headache being perhaps sorting.

    The simplest kind of procedural generation is done on a 2d grid. This can be represented by a 2d array which will provide a value for each grid position. Next you as the designer need to choose what the values mean.

    For a continent type you could use say 0 for water and 1 for land. For a dungeon you could use 0 for floor and 1 for walls. It just all depends on what you want to generate. Also there is no reason why you couldn't use 2,3... and so forth for more terrain types, again it depends on what you want to do.

    Note at this point we just have a data representation of the map. If we want to get a visual of it we need to loop over the array and create objects at those positions.

    For example if each tile is 32x32 pixels and the tile's origin is in the center then you can create the map with an event like so:

    Array: for each xy element
    --- Array: current value = 0
    ------> System create water on layer 0 at (Array.CurX*32+16, Array.CurY*32+16)
    --- Array: current value = 1
    ------> System create ground on layer 0 at (Array.CurX*32+16, Array.CurY*32+16)[/code:y0phpsp3]
    
    Or if your sprites are isometric then you can do this.  Note: a 32x32x32 isometric cube will have a 64x64 pixel image.
    [code:y0phpsp3]Array: for each xy element
    --- Array: current value = 0
    ------> System create water on layer 0 at ((Array.CurX-Array.CurY)*32+320, (Array.CurX+Array.CurY)/2*32+16)
    --- Array: current value = 1
    ------> System create ground on layer 0 at ((Array.CurX-Array.CurY)*32+320, (Array.CurX+Array.CurY)/2*32+16)[/code:y0phpsp3]
    
    Well, then on to more about the generation.  The most simple generation other than setting all the array to one value is to set each value to be randomly 0 or 1.
    [code:y0phpsp3]Start of layout
    Array for each xy element
    ---> Array: set value at (Array.CurX, Array.CurY) to choose(0,1)[/code:y0phpsp3]
    
    Beyond that there are a lot of different ways you can generate the maps.
    
    Instead of set setting individual grids you can set horizontal or vertical lines and filled rectangles by using "for loops".  
    
    For terrain you can use the "noise" addon which will give nice perlin noise instead of staic noise.  I've also used a smaller separate array and interpolated it onto the larger array for a more globular noise. 
    
    For the wall bit do a search for "bitwise" for a method to choose a image based on what's around it.  It also can be used for the water shoreline.
    
    To have a land mass that doesn't have any inaccessible areas there are basically two ways to go about it.  One is to pick a spot with land and do a "flood fill" there to mark anything connected and then check for values of land that isn't marked.  A second method is to only grow from existing land so you always know it's connected.
    
    Another topic to look up is "cellular automata" which can be useful at times.
    
    cheers
  • Thanks. I'll look into what you said.

  • This might give you some ideas. http://www.vlambeer.com/2013/04/02/rand ... and-kings/

    You might also look into how Spelunky generates it's levels. It sort of combines authored content with procedural generation by having a set of pre-made rooms that are stuck together semi-randomly.

  • This might give you some ideas. http://www.vlambeer.com/2013/04/02/rand ... and-kings/

    You might also look into how Spelunky generates it's levels. It sort of combines authored content with procedural generation by having a set of pre-made rooms that are stuck together semi-randomly.

    That Wasteland Kings example looks very interesting. From what the article said, it looked like the floormaker is a sprite that is spawing floor tiles as it goes, and then each floor tile spawns a wall on one of its corner. It seems like this would generate a lot of overlapping tiles since some would get placed on the same spot. It also looks like the tiles are very simple and blocky without much need for variation. I would rather make mine a little bit better looking since it would fit my game better.

    I do like the idea of Wasteland Kings map generation. It will also create areas that are accessible with only a small chance of something going wrong.

    I looked up a bit on bitwise map creation as R0J0hound suggested. It looks like it can be done on an array where it simply checks to see the value of the neighboring elements using something like "array.curX +1". I really can't find many good ways to reference a single element on an array.

    Here is an article I found that was useful on bitwise stuff:

    http://www.saltgames.com/2010/a-bitwise ... -tilemaps/

    I tried to find a way to combine the two methods. The only way I saw to do it was to create a sprite for each tile, put it on the layout in the correct spot, put them in a family, give the family an instance variable, and then have the floormaker piece change that variable when it overlaps them as it moves around the layout. Then, the sprites would modify the value of their corresponding array element, then they would be deleted. Then, after all that, the bitwise part would set in checking values on the array. This is a bit tedious since the layout needs to have one sprite for each array element which is a lot for big maps. I guess I could have used a second animation frame for the sprites as my trigger instead of an instance variable though.

    I guess it could be done without sprites if I could move around on an array moving from one element to the next randomly and setting the values to either a 0 or 1 if I want a floor tile or wall tile. I'm not really sure if I know how to do this. It sounds like it would be an easier approach though.

    I figure my biggest challenge right now will be to make everything work. It's a party based game, so all 3 heroes need to be spawned correctly and not stuck in a wall. Then, I need to place enemies which shouldn't be too hard. I also need to make sure each part of the map can be accessed if my game goal is to kill all enemies.

    I still feel like I will need to sacrifice some graphical detail to get this to work. It's getting late so I need to call it a night. I hope I didn't miss anything with this post.

  • DrewMelton

    I'd go for using separate animation frames rather than separate objects.

    Here's a bitwise example here that uses the tilemap instead of array, but the concept is about the same.

    tilemap-auto-tile-help_p721581?#p721581

    I had a bit of a go at making an example in isometric. Art is time consuming for me and I wasn't able to find a free tileset that has all 16 combinations required for the bitwise method. I was able to use a modified approach with what I could find though.

    http://opengameart.org/content/cave-tileset

    https://dl.dropboxusercontent.com/u/542 ... tile3.capx

    I also found a useful general reference on isometric here that may be helpful:

    http://gamedevelopment.tutsplus.com/tut ... medev-6511

  • DrewMelton

    I'd go for using separate animation frames rather than separate objects.

    Here's a bitwise example here that uses the tilemap instead of array, but the concept is about the same.

    tilemap-auto-tile-help_p721581?#p721581

    I had a bit of a go at making an example in isometric. Art is time consuming for me and I wasn't able to find a free tileset that has all 16 combinations required for the bitwise method. I was able to use a modified approach with what I could find though.

    http://opengameart.org/content/cave-tileset

    https://dl.dropboxusercontent.com/u/542 ... tile3.capx

    I also found a useful general reference on isometric here that may be helpful:

    http://gamedevelopment.tutsplus.com/tut ... medev-6511

    Thanks for the capx!

    I'm going to spend the rest of the evening playing with this. I may implement a sort of Minecraft ability to destroy tiles and look for treasure or to create a path. That way, I won't have to worry about rooms being isolated. If an enemy gets created in an isolated room, I can make him into a monster of some sort rather than human enemy which would look silly.

    It might look a tad silly have a mage, fighter, and thief able to use a pickaxe, but it might be fun as well. Plus it would open up more gameplay options and give people more to do than fight.

  • R0J0hound or Ahr Ech or anyone else, can someone have a look at this capx and see what is wrong.

    I found an old cap file for construct classic, and I wanted to remake into construct 2 so I could test it. However, it is not working as it should. Some of the logic and terms are different, so maybe something is throwing me off.

    Here is the tutorial with the old cap file for reference if you want it. https://dl.dropboxusercontent.com/u/581 ... al.doc.pdf

    I have attached my remake. Can someone look at it with fresh eyes and see where the error is? I was trying to follow the example as closely as I could, so maybe something needs to be written differently or maybe I just messed up and didn't realize it.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • I can't open the capx at the moment but you'll have to tweak your array events slightly.

    Construct classic arrays are 1 based so to access the first element you'd use

    Array(1)

    Array(2) for the second and so on.

    C2 uses 0 based arrays, so the expressions to access the first two elements would be:

    Array.at(0) and array.at(1)

    So I think if you subtract one from the array indexes throughout your capx it should fix it.

  • R0J0hound Yeah, I made sure to allow for that, though it was still a little off putting, so hopefully I didn't miss any.

    I have to call it a day. I'll try again tomorrow. If you get a chance to look at it, let me know. It's probably something simple that I keep glossing over.

  • DrewMelton

    I compared your capx to the original cap and found the issue.

    In events 7-10 you need to change the "miner.CurX" expressions to "miner.At(0)" or "miner.At(1)" like in the CC cap and it works.

  • R0J0hound Sweet, it works! Thanks!

    I also noticed that when I clicked to redraw map, it was actually adding on rather than recreating, so I added an event under on start of layout to say for each xy of map to set curx and cury to 0 so it starts fresh each time.

    I guess the next step is to get enemy and hero placement sorted since this will have to be automated as well. And then I need to decide on what kind of tiles, slanted or straight. So, time for me to get work on that. Everything is coming along nicely though.

  • R0J0hound Hey, I hate to bother you again, but you seemed most likely to know the answer to this.

    I added on to the capx I just posted to include isometric tiles. The problem is that I'm only getting half a map now. Here is a screen shot. Please note that the graphics were made quickly and are a bit crude.

    You can see from the mini-map I set up in the bottom right that I'm not getting full coverage of the tiles. The blue is the background.

    Also, the green tiles seem heavily biased towards the left side most of the time.

    I tried adding some elements to the map array, but it never seemed to fill all the way, and the object count was getting too high for me.

    So yeah, it's getting really close and starting to look pretty cool. If I can work out a few more bugs, it'll be pretty sweet.

    Changes from last capx:

    Able to destroy tiles (changes animation and removes solid)

    mini-map added. Draw and refresh by right clicking. (also focuses on player afterwards)

    ground tiles changed to iso tiles. Wall tiles change to iso tile with height added.

    slight modifications in the way it creates the random map

    hero spawns on random ground tile and destroys wall tiles nearby (needs work)

    scroll with directions arrows on your keyboard

  • DrewMelton

    If you set the layout width to 6000 and change the x expressions in events 37,38 from "(map.CurX-map.CurY)*75" to "(map.CurX-map.CurY)*75+3000" then the minimap will be more centered. You can do something similar for the vertical space.

  • R0J0hound Thanks, I was able to play around with those numbers and get it centered. I would have tried that before, but I thought maybe it was supposed to fill the whole thing. Now that I really think about it, it makes sense that it does not. Thanks again.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)