A downloadable Engine for Windows

Buy Now$4.99 USD or more

A basic dungeon crawler engine (Game Maker Studio source file) that creates a map of any desired size, populated with rooms that can be 1x1, 2x1 or 2x2 'map cells' big.

  • Rooms are populated with enemies/treasure and decorated by passing selection scripts as arguments to the dungeon generation functions; these can be as simple as a choose() statement or be arbitrarily complex and access data in the dungeon data structure to make their choices.
  • Rooms are categorized as 'big' and 'special' separately, and can be 'special' in one of several ways (treasure room, secret treasure room, boss, player start point, ...). The meta-data is accessible by dungeon room ID and lets you adapt enemy spawn rates and other things as you see fit (such as always spawning zero enemies in the player start room, and using a set dungeon pattern for this room so it always looks the same)
  • Dungeon rooms use separate tilesets for walls, floor and obstacle objects. This enables you to partially combine biomes, such as forest clearings mixing resources for forest and plains rooms.
  • Dungeon room models are created using a sprite-based system; you can add in new room blueprints very quickly and easily.
  • Macros and constants are used to maximize legibility of code. No 'magic numbers' are in the code.
  • Big rooms are created by mirrored copies of a small-room blueprint, making big rooms symmetrical and have access to as many different shapes as smaller rooms do.
  • Smooth scrolling that follows the player character but won't move onto the next room until you cross the boundary. Only objects in view are active, speeding up the game processing and ensuring enemies in other rooms don't do anything stupid while you're not watching.
  • The engine is kept very general; enemies and items are just visual placeholders with very basic behavior. You can just load the resources from this engine into an existing game to get dungeon crawler functionality! (If you do this, make sure you also copy over the macros/constants from the dungeon generator source file).
  • Code is cleanly separated in multiple scripts and grouped by functionality, letting you find what you look for easily should you desire to tweak anything to better suit your needs.
  • Can be used for commercial projects; credit appreciated but not required.
  • Uses Floofpaws' surface sampler scripts, which are released in the public domain.


Buy Now$4.99 USD or more

In order to download this Engine you must purchase it at or above the minimum price of $4.99 USD. You will get access to the following files:

Source Code (GMS 2.3) 480 kB
Source Code (GMS1.4) 76 kB

Download demo

Demo Executable 2 MB
License Agreement 22 kB

Development log


Log in with itch.io to leave a comment.

(1 edit)

Hey, sorry for bugging you again.. figured you might know this better!

Been having trouble getting surfaces showing up in the engine. Used the demo project without any other changes than a shadow surface and it didn't work there either, so it's purely the engine causing it. Made an instance that creates a shadow surface at depth 1999 (floors are 2000, walls are 1998, creates more depth), this is the size of the view and is drawn at the camera using camera_get_view_x(view_camera[0]), camera_get_view_y(view_camera[0]).. if I put this in a new empty room, it works, but not in the main game room, just shows up as transparent in the debugger and no shadows anywhere :( Is there anything you can think of in the code that'd cause this? I can't seem to get any extra surfaces working.

The only explanation I can think of is "something goes wrong when trying to draw to the surface", I know alpha + surfaces is a bit of a wonky mix. I did a bunch of searches through the codebase to see if there's any unresolved alpha settings that might carry over, but I couldn't find anything suspicious. So... derp, back to square one.

Some things to investigate...

  • The size of the view might be zero at the moment the surface is created, perhaps? Try printing out the surface's size with a debug message after creating it.
  • If you use draw_clear_alpha to fill the surface with both color (preferably something like c_fuchsia so it's possible to tell the black background from a black surface) and 100% alpha at once, does it show up properly?
  • If the object that draws the surface draws something else at the same time (e.g. a gradient circle with draw_circle_ext, large enough to be visible even if the thing is offscreen a bit), does that work or is it also invisible? Depth sorting, accidentally turning off visible etc all could explain it being gone.
  • This goes without saying, but do you re-create the surface if it gets destroyed? It doesn't happen all the time on a desktop target, but it's definitely going to get destroyed eventually.
  • I noticed the view/HUD control object has a depth outside the 16,000 range, perhaps that could lead to oddities in the depth sorting? (I had similar issues when doing the DDG2 port job, changing depths had absolutely no effect when objects were outside the valid range). Changing the object's depth to be in front of everything else (e.g. -4000) could help shedding light on this; if it draws at the new depth the depth sorting is the reason why the surface is invisible.
(1 edit)

1. Surface size is correct, according to the debug message.
2. If I do c_fuchsia on the draw_clear_alpha, the screen does turn that colour.
3. The circle appears, on top of everything..
4. Always recreated!
5. Changed the view controller depth, no noticeable difference.

Getting a little bit of hope with the circle showing up, I'll mess around with depths and see what I find!

2. If I do c_fuchsia on the draw_clear_alpha, the screen does turn that colour.

Are you 100% sure you draw to the surface when doing this? It sounds like the symptom of not surface_set_target-ing it first (clearing the entire screen instead of the surface). And not surface_set_target-ing it would also explain why nothing is drawn to it.

Oh, correction, the entire screen doesn't turn that colour - only the floor tiles. The walls are all 'above' the clear_set_alpha as are the instances.

This is the code I'm using for the surface

(1 edit)

I think I've spotted the issue - when you set the drawing target to a surface, 0,0 is the top left corner of the surface. However, you don't always draw the surface at the 0,0 room coordinate, so drawing sprites at x,y will displace them with whatever the view top-left corner currently is. Draw the shadow sprites at x-cx, y-cy instead and it should work. (It probably worked when you did it in a separate room since you didn't move the view away from the top-left corner)

(1 edit)

Hey! I just bought this, trying to manually merge it into the game I'm working on (so I can learn what every script does).. I noticed this uses legacy tile code, whereas my game has tile layers for the walls, floor and foreground (so if I move to the bottom, my character is slightly covered by the ceiling to give the illusion of depth)

I'm a little confused as to how I'd modify your code to work with tile layers and the new tilemap_set functions - if I change "dungen_render_tile" to be tilemap_set, the game just straight up doesn't load - no errors, just hangs on 'biomes & metadata assigned~'. I also used tilemap_get_at_pixel within dungen_render_room to try to get the correct cell IDs for the tilemap_set, but it still hangs the same way.. any help would be appreciated :(

(1 edit)

I'm pretty sure the game hangs because dun_room_pos_free only returns true if there's a tile of the wtd_FLOOR type on the position (which also uses the legacy tile function), and there's a number of loops to place enemies/treasure that will loop indefinitely checking random positions until they find a free spot. (Completely blank spots are treated as collisions to stop points outside of the dungeon to count as empty) If no spot is free since the collision-checking function is broken, it will loop forever, and since you now don't spawn the legacy floor tiles anymore, it will never find a free spot.

To fully fix this, you'd need to replace all the legacy tile functions in the engine with something adapted for your multi-layer solution:

The first 3 matches delete wall tiles and overwrites them with floor tiles at positions that should have a door, the next 3 matches are the tile rendering you've already replaced, the four subsequent ones are in the collision-checking function that's currently causing the crash, and the final match is just an effect object that you don't need to worry about at the moment.

My idea for the fix to dun_room_pos_free is to replace the wall/floor checks with checks to see if the tilemap at the wall / floor layers has a nonzero tile, since walls are checked before floors it should work without changing the order/priorities.

Thanks so much for the response! I'll study this when I get back into it, though there was another thing that was worrying me - I have two GMS2 windows open, one that's just this imported project, and my game which I've imported all the scripts/objects to. I rearranged my tilesets to look like the ones in the demo (6-wide floor, then 6-wide wall below it) just to see if it'd work.. but it's black. My character renders, doors appear, but the background is black.

Not sure if there's something in my code that's causing this, but I can't figure out for the life of me why none of the tiles are rendering with no changes whatsoever lol. The same code works fine in the actual demo project.

If I can figure this out.. and get it to work with the legacy, it'd be a lot easier to start moving it over to the new layered system because I'd be able to see it working..

I pretty much changed all of the compatibility scripts for the layer (the created tile_add etc.) to use the new functions.. and the game loads, no hanging! I still have the invisible problem though.. 

How does your new version of dungen_render_tile look? New-style tiles changed from coordinates to a 0-N index so if you pipe in the same coordinates as before it would probably create tiles outside the range of the tileset. Also, the example tileset is organized in a special way and this is used by _render_tile (first row has 6 floor tiles, second row has 6 wall tiles, third has 6 obstacle tiles, so it picks an x coordinate between 0 and 5*TILESIZE and an y coordinate based on the tile type), if your tileset is arranged in a different way you'd need to adjust how the coordinates are picked to suit this. Okay I didn't see your first message, seems like you already tested the tileset arrangement issue.

As an intermediate debug step, try creating objects rather than tiles (with instance_create_depth) and make bright-colored squares for the placeholder walls and floors, this should at least tell you if the spawning is done correctly. (I would wager it's done correctly if the doors show up in the right spots, but it's best to make absolute sure).

If you still don't see anything when spawning placeholder objecst, you could try adding a show_debug_message() to their create event where they print their x/y coordinates (if those messages show up, but you can't see the objects, just compare with the player's spawn point to figure out where they spawn; if the messages aren't printed, the objects aren't spawned at all)


Thanks for all the help! I got it working, just trying to figure out bitmasking for the wall tiles. This is what I got so far, if you're interested in how I'm destroying your code:

The numbers correspond to the bitmask, so I can debug it easily and place walls properly. The red square is a solid placed through code on the walls. Once you get into it it's very easy to modify this engine, great work on it <3

Hi Yal!

I was wondering if it's possible to manipulate the code in some way so that pre-made rooms could be randomly chosen, rather than the room sprites? I'm still rather inexperienced with programming, but this engine will help me learn a lot more!

Thank you~

(1 edit)

This is a wall of text, sorry about that x3

The rooms aren't GameMaker rooms, everything is created in a single room using the data in the room-sprites. It shouldn't be impossible to get premade rooms working, though... the two main scripts you should look into are dungen_render_room() and dungen_spawn_contents() for actually creating room contents. (Specifically the code block with the "If inside the room, we need to actually look up what tile type to spawn." comment... remove that, and then add code after the loop to create the stuff from the premade room.)

This is assuming you want to replace the sprite-sampler system with your own premade room system... if it's for what's commonly called "vaults" (occasional handmade rooms to spice up the randomness) you could add them to dungen_init_specials_list (although that still uses the sprite-based approach) and adding a new sprite to dungen_rooms_assign_biomes for it.

Another thing you could check out for a place to insert your code is dungen_rooms_spawn, once you read rrr you could check global.dungeon_room_type[rrr] to see if you've got a room of a special type, and then spawn it in a different way. (Don't forget to add walls and doors, since _render_room does that too).

I've not thought too much about HOW to make those premade rooms, but there's two easy options. In Studio 1 rooms are XML files, so you could make the rooms in the room editor, copy the files to included files, and then just parse the XML from them.

In GMS2 they're JSON files that don't contain the object names, so that's a bit trickier. I'd go with a bit more involved approach: get into the room, have the creation code of an "room exporter" object run something like

var s = "";
var nl = "
  if(id != other.id){
    s += instance_create(string(x) + " + xxxx," + string(y) + " + yyyy," + object_get_name(object_index)) + ";" + nl;
show_message("Level copied to clipboard!")

Bam, now you have your clipboard filled with a GML script that creates all those instances. Paste it in a new script in your game, and then when you wanna create that room in a dungeon, call it. Just set the variables "xxxx" and "yyyy" to the room's top-left corner coordinates in the new dungeon.

Oh, side note... just remembered instance_create() has been removed in GMS2 and it's now instance_create_layer() or something like that... you'll need to modify the code snippet to generate the correct functon name (and add a layer name) if you're going to use it in GMS2, but hopefully that's easy enough. (I don't use GMS2 a lot myself, I mostly import projects originally made in GMS1 and then export them without doing any actual editing)


Woah, so much information! Thank you for the amazing reply Yal.  *Time to study*

hello, i am searching a very special dungeon generator... with "stick rooms" functions... could we talk about that?

Sure. First of all, what exactly is a "stick room"? Is it related to tree data structures in some way?

Predefined rooms can be accidentally glued together. These predefined rooms are stored somewhere and used by the generator when generating.

This engine uses predefined room layouts, room maps are stored in bitmaps so you can quickly draw new rooms using Game Maker's sprite editor. There's also separate sprites for normal rooms, boss rooms, player start rooms and treasure rooms, so you can easily have some layouts only be used in some contexts, and this system probably wouldn't be too hard to extend either (e.g. you could randomly change some rooms' layouts to layouts from your "SPECIAL STICK ROOM" if you want 2-3 stick rooms in the middle of all the normal ones).

i need one big room, and this room is generated of any room "parts" and stick together...

Everything is still placed in a single GM room... the view scrolling effect is just there because the generator is inspired by Binding of Isaac, if you remove it and have the view follow the player normally it becomes a single cohesive room.

FATAL ERROR in Vertex Shader compilation
ShaderName: shader_hurtflash
D3DXCompile failed - result
at gml_Object_parent_enemy_Draw_0

If this error is displayed, it means your computer doesn't support shaders. One possibility could be that you don't have the DirectX 9 runtime installed, you should be able to get it from here: https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=35

If that fails, the problem is probably that your GPU doesn't support OpenGL, and you'll need to remove the shader from the game (and remove the code in parent_enemy that sets and resets the shader before drawing, so you don't have a reference to a nonexistent resource).

Sorry about this, but I am extremely dumb and I'm having trouble. I purchased this engine mostly to figure out how to generate room layouts based on predefined blueprints but I can't for the life of me figure out how it works in this engine. I've been scouring all the scripts to figure out where the blueprints are defined or how to make new ones and it's driving me crazy.


The rooms are actually defined using four sprites (one pixel corresponds to one tile in the room, each color means a different type of tile) - Sprites-->Room Maps will give you those, and their names should explain the purpose of each map. Just add more subimages to a sprite and they should automatically get added to the random selection.

You'll also need dungen_render_room() and dungen_render_tile() to actually create a room from the blueprints, though. (And also all the scripts in the folder Scripts-->Assist Scripts--->Floofpaws' Sampler Extension). I think they're pretty much standalone enough that they can be used on their own without the rest of the dungeon generation structure around them with just some small changes to dungen_render_room():

  • Remove the part that spawns enemies and treasures.
  • Remove the lookup of the "doorflags" variable and pass that as an argument instead.

In either case, the important bit is how dungen_render_room() uses a sampler to read the sprite data. The colors that are used to represent different types of tiles are defined in the list of macros, under __VaultMapData__, and these constants is what dungen_render_tile() is checking for.

If there's anything more that's unclear, feel free to ask :3


I thought it worked something like that, and now I know what my problem was:

when you import another project, the sprites show up as black squares in the resource menu until you view or edit them. so my eyes just sort of passed over these seemingly unhelpful square sprites. Thanks for replying!