Spawn prebuilt rooms in procedural generation

J

Jacob Thrasher

Guest
So I want to start working on a procedurally generated dungeon crawler. Essentially I want the following to happen:

-Create a bunch of rooms by hand
-Randomly place those rooms throughout the level
-Connect with pathways and other things

The problem is with the second step (or really the first two). What is the best way to go about placing custom rooms throughout the level? The only thought I have is to create each room as a sprite with weird hitboxes where there should be obstacles and then convert that to an object to place. That method seems entirely too convoluted, but I am having trouble determining a better solution.

Is there a way to place actual gamemaker rooms within a parent one? Or is there just no good way to do what I am trying to accomplish.

Thank
 
R

robproctor83

Guest
Maybe I am wrong, but I don't think it is possible to use normal rooms in this regard as I don't believe there is anyway to "merge" multiple rooms together like you want. So, your idea about making a sprite and then looping over the pixels to convert to objects is actually a fairly common method for doing this. It's not as bad as you may think, and since it essentially only needs to run at the start of the room it's not such a big deal if it's not totally efficient. The only real downside I can think of with this is that depending on the size of your rooms and how many you have you may end up using a lot of room in your texture page. Because of that it may be a good idea to move these sprites into their own texture group so that it doesn't take up space in your main texture pages and hopefully not create unnecessary texture swaps once you have generated the rooms.

With that said, you could do something terrible and gross like making a bunch of rooms and then looping over them and making some convoluted data structure that retains the placement of all objects in relation to the room it was loaded from, then you can define in something what rooms go where and then you can loop back over that huge set of room data and place things where they go, BUT this is not a good idea and your solution with the image is much much better.
 

Tsa05

Member
GameMaker's way of handling rooms makes it impossible to be in 2 rooms at once. Slightly different strategy:
You build your pre-built room layouts, and then create a "room reader" object that collects up allll the objects in the room and gets their type, scale, and position...and writes that down.
You bundle this data into the game and use it to construct pre-made room segments. That's how it's usually done; you use the room editor for design, then bake the data.

Something like this in the Create event of a "room scanner" object that you add to the room to be scanned:
Code:
global.roomData = ds_list_create();

with(all){
    var obj = ds_map_create();
    obj[?"object_index"] = object_index;
    obj[?"x"] = x;
    obj[?"y"] = y;
    obj[?"image_xscale"] = image_xscale;
    obj[?"image_yscale"] = image_yscale;
    obj[?"layer"] = layer_get_name(layer);
    ds_list_add(global.roomData, obj);
    ds_list_mark_as_map(global.roomData, ds_list_size(global.roomData)-1);
}
That'd leave you with a list of stuff for that room, and you might write that to a file, or store it for later or...whatevs.

Then, you'd have a script to bring that stuff into your procedural room:
Code:
///    @function script_create_scanned_room(ds_list, [x-offset], [y-offset])
///    @arg    {real}    ds_list        A list of ds_map objects with info about the object in a room
///    @arg    {real}    *xOffset    Optional x amount to offset this set of objects
///    @arg    {real}    *yOffset    Optional y amount to offset this set of objects


/*
*    This script relies upon having layers
*    with the correct names in your room
*/
var dataList = argument[0];
var offX = 0;
var offY = 0;
if(argument_count>1) offX = argument[1];
if(argument_count>2) offY = argument[2];

var L = ds_list_size(dataList);
for(var i=0;i<L;i++){
    var data = dataList[|i];
    var o = instance_create_layer(data[?"x"]+offX, data[?"y"]+offY, data[?"layer"], data[?"object_index"]);
    o.image_xscale = data[?"image_xscale"];
    o.image_yscale = data[?"image_yscale"];
}
 
Last edited:
J

Jacob Thrasher

Guest
GameMaker's way of handling rooms makes it impossible to be in 2 rooms at once. Slightly different strategy:
You build your pre-built room layouts, and then create a "room reader" object that collects up allll the objects in the room and gets their type, scale, and position...and writes that down.
You bundle this data into the game and use it to construct pre-made room segments. That's how it's usually done; you use the room editor for design, then bake the data.

Something like this in the Create event of a "room scanner" object that you add to the room to be scanned:
Code:
global.roomData = ds_list_create();

with(all){
    var obj = ds_map_create();
    obj[?"object_index"] = object_index;
    obj[?"x"] = x;
    obj[?"y"] = y;
    obj[?"image_xscale"] = image_xscale;
    obj[?"image_yscale"] = image_yscale;
    obj[?"layer"] = layer_get_name(layer);
    ds_list_add(global.roomData, obj);
    ds_list_mark_as_map(global.roomData, ds_list_size(global.roomData)-1);
}
That'd leave you with a list of stuff for that room, and you might write that to a file, or store it for later or...whatevs.

Then, you'd have a script to bring that stuff into your procedural room:
Code:
///    @function script_create_scanned_room(ds_list, [x-offset], [y-offset])
///    @arg    {real}    ds_list        A list of ds_map objects with info about the object in a room
///    @arg    {real}    *xOffset    Option x amount to offset this set of objects
///    @arg    {real}    *yOffset    Option y amount to offset this set of objects


/*
*    This script relies upon having layers
*    with the correct names in your room
*/
var dataList = argument[0];
var offX = 0;
var offY = 0;
if(argument_count>1) offX = argument[1];
if(argument_count>2) offY = argument[2];

var L = ds_list_size(dataList);
for(var i=i;i<L;i++){
    var data = dataList[|i];
    var o = instance_create_layer(data[?"x"]+offX, data[?"y"]+offY, data[?"layer"], data[?"object_index"]);
    o.image_xscale = data[?"image_xscale"];
    o.image_yscale = data[?"image_yscale"];
}
I really like this solution. I'll work on implementing it. Thanks for the help!
 
Top