Procedurally generated dungeon crawler with turn based combat - how to best switch between dungeon and combat map?

Hi all,

to explain the project: The player can enter a dungeon similar to something like Persona. On entry the dungeon is procedurally generated from small “room modules” that are saved as blueprint actors. The player can explore the dungeon, find enemies and ultimately finish the dungeon to go back to the hub world.

On collision with an enemy the game is supposed to switch into turn based combat mode. I want to load the combat map and some data for additional party units that are not in the dungeon and when the player finishes combat return back to the dungeon.

Now I need to find some way to save the state of the dungeon as well as bringing some player data back and forth. Player data I could potentially handle through the game instance but my biggest question is the dungeon itself.

I have started looking into save game slots or something more manual through the game instance but I’m not sure what the best way to do this is. Theoretically I would have to save all rooms that were placed and their transform, all positions of enemies and if they were defeated, later on potentially chests and even more. I want to avoid the dungeon being regenerated every time the player comes back from combat.

This sounds like such a simplem ask but the solutions I find seem quite convoluted. I’d love some tipps on what to best look into, I don’t expect any fully fleshed out solutions at this point.

First:
Streaming level does not save actors state, so after you unload level, all actors will have state reset to default.

Depends on size of dungeon and if you want to have savegame during dungeon crawl.

I would just make system to save whole dungeon tile by tile. Make some struct that can save single tile state. Limit gameplay so you do not need to save random items in tiles (like when player drops used potion, or any item, you just remove it instead saving to tile), for enemies they should be either alive (Spawned) or dead (removed). Just simplify state of tiles as much as you can (remove all stuyff that does not change gameplay much).

When data per tile is minimal just create savegame, save all tiles.

For dungeon state (default/starting state) look into data assets.

  • create data asset that describes single tile
  • create separate data assets that remembers layout of dungeon.
  • not sure if your dungeon is using grid or just any level shape like in unreal. You can create separate tiles/levels, then use data asset with info how to combine them

Really hard to guess what you need.

Interesting, I haven’t looked into data assets for this at all.

How the dungeon currrntly works:

  • the generator spawns a start room which is a blueprint with some geometry and an exit
  • at the location of the exit the generator spawns a random room out of 6 (or however many i want) that has one or more exits
  • every time a room is spawned all exits in the room go into an array of usable exits
  • the generator spawns more rooms on random exits until the number of rooms is reached
  • each room has slots for enemies or treasure chests that are spawned when the dungeon is complete
  • once everything is done the generator closes all unused exits and places a teleporter back to the hub in the last room

I’m really curious how you would save the dungeon layout into a data asset. I wouldn’t know where to start, could you elaborate on that a little?

For proceduraly generated stuff see this:

So you need location and rotation for each room.
You can store rooms/dungeon with just single TRANSFORM + some integer as type/index of room.

If you use Data assets for it, you can create such thing and store in folder. Then either index or filename or soft reference to data asset will determine dungeon CELL.

Dungeon data will be array of transforms + that cell data asset.

I made similar (hovever overcomplicated a bit) system:
It is done for RTS in space and instead of dungeon i wanted to create planetary systems.

  • used data assets instead of structs to define planets (like visuals, economy, some backs story). 3 separate data assets so i could mix them for actual planet.
  • then separate data asset for thumbnail and skybox
  • then i made editor tool/widget to create such data assets manually (i had procedural generation, but this adds manual tool).
  • with data assets definition of whole level (skybox and planets/system) was just struct that holds filenames of data assets i want to use. Then just simple function that loads it all from filenames.

Overcomplicated part:
Instead of making struct of transforms and int values, I encoded it all as HEXADECIMAL strings, then stored that strings in simple string array. Reason for this is that in editor tool i could copy paste such strings to duplicate planet data. So in level i could create planet, tune its economy and looks, then generate that HEX string and copy/paste into editor tool to use later.

That’s amazing insight, thank you so much. I’ll have a look and see how i get on with this <3