Project architecture for a procedurally generated metroidvania map

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Zennyth

Hi everyone,

I’m not that familiar with Godot but I am comfortable in development and a quick learner. I’m using C# for this project.

I’m currently developing a metroidvania with a generated map. Here is my simple workflow:
Graph Generation with graph rewritting → Transformation with spatial graph → Instantiation of Biomes, Chunks, Rooms → Generation of the environement

I would reproduce a map system like Hollow Knight with “chunks loading” so the “biome” isn’t fully loaded. I’m working with graph example and the"Transformation with spatial graph" is mostly functional but i’ve no idea how I should implement the scene instantiation and the scene manager.

Here is the Nodes that i’m working with:
World (Basic Biomes graph generation)

  • Camera
  • Biomes (Basic Rooms graph generation)
  • Instances
    • Biome : Biome’s type scene (Instanced by the node named World)
      • TileMap
      • Rooms
        • Instances
          • Room (Instanced by the node named Biome)

I have a scene for each type of biome with a TileMap to draw on but like I said I dont want the entire biome to be drew nor update at the same time. And I dont know the best way to do it properly, thats why there’s no Chunks on the tree.

This project is a proof of concept, in it’s early development phase and i’m doing this on my free time.

Have you any ideas on how to manage the scenes ?

if i understood correctly, you need to procedurally fill a tile map in run time.

i think there are hundreds of ways of doing it, the best one depends on your specific project.
The easier i can think of is just fill the cells around the camera, and update them as the camera moves around, but again, it depends on the way you structured the tile filling algorithm

Andrea | 2021-10-02 13:44

Thank’s for your time and response,

but I dont think I need to procedurally fill a tile map, the most common way of designing map levels is by creating scenes and then switching between them as the player progresses through the game.

I need a similar process but with generated scenes not handmade ones.

For now each biome is a node that contains rooms, I would like a system that could switch between biomes for example.

Zennyth | 2021-10-02 15:23

Sorry i think i misunderstood your question then.

To manage scenes in runtime is identical between “handmade” ones or scene create via script.
You can simply instance them and then add to the tree as child of something else.
Then, if you dont use them anymore, you can decide to queue free, or to remove them from the tree (so you can add them later on again),-
However i think that if you knew how to do it with handmade ones you already figured out how to do it yourself, so i guess i misunderstood your question again

Andrea | 2021-10-02 15:34

Sorry I’m not an english native speaker, your misunderstanding is mostly due from my explications.

So I should use a singleton that knows the world structure and then manage the switch between scenes ? Of course I will need to include the character into the next scene.

Zennyth | 2021-10-02 16:35

you could do it with a singleton, but it is probably easier to attach a script to the parent that contains all the scenes you need to switch between, and let him do the dirty job

something like:

  • Parent node
  • Scene1
  • Scene2
  • Scene3

and in the parent node attach a script that manage new scene creation, scene removal, and maybe player position in the scenes?
Again, a lot of options, it depends on how you plan to use those scenes

I suggest to look for some tutorial, not for the coding itself but to better understand how to properly use the scene trees

https://www.youtube.com/watch?v=WUARiOGSGKY

Andrea | 2021-10-02 16:46

Ok so imagine that i would have 3 biome instances and each biome has their own tilemap.
Biomes (Node) (SceneManger script):

  • SandBiome
  • ForestBiome
  • Forest2Biome

How would I switch between SandBiome and ForestBiome ?

Zennyth | 2021-10-03 14:23

This strongly depends on what the biome scene is supposed to do: is it only a graphical + collision node? does it need to “remember” player modifications (eg: an open chest need to be open when the player come back to the scene later)? does it make frame by frame calculation that need to continue even when scene is switched, or is it ok to freeze everything when on another scene?

The easier way to do it is to simply have 1 biome loaded at a time, which means queue_free() the existing and load a new one when switching.

func switch():
 get_child(0).queue_free()
 var new_biome=load(folder_path_to_scene_biome).instance()
 add_child(new_biome)

change_scene() and change_scene_to() does the above in a single method

in case you need to recover the previous state, you can either save the “modifications” on a set of variable (maybe a resource or dictionary) and then recover then and apply them to the newly added biome.

Or you could set aside the unused biome with a simple biome.hide() (collision and script will still work).
In case you want to stop everything in the unused biome, you can implement a scripted functions to make everything stop working when not needed

func switch()
 $SandBiome.stop_activity()
 $ForestBiome.recover()

func stop_activity():  #it will obviously be much more complex than this
 set_process(false)
 $CollisionPoligon2d.disabled=true
 hide()

Or, you can remove unsused biomes from the tree with remove_child() and store the node in a variable. This probably looks easier than it actually will be, because it is true it will automatically store every modification and recover it later, but the orphan child nodes needs special attention, because every connection with external nodes will be broken, therefore you might end up with a lot of errors.
So you again need to implement some sort of “stop” function

var biome1
var biome2
var current_biome=null

func _ready():
 biome1=load(path_to_biome1).instance()
 biome1.stop_activity()
 biome2=load(path_to_biome2).instance()
 biome2.stop_activity()
 switch(biome1)

func switch(biome_to_switch):
 if current_biome!=null:
   remove_child(current_biome)
   current_biome.stop_activity()
 add_child(biome_to_switch)
 current_biome=biome_to_switch
 current_biome.recover()

i know this is VERY generic, but i hope you could get some inspiration
in the docs they cover this topic here:
Change scenes manually — Godot Engine (stable) documentation in English mostly they give the same advices, maybe with a little more examples and explanation on memory usage

Andrea | 2021-10-03 18:18

Thank you very much for your detailed answer, I’ll keep you inform over the progress I’ve made.

Zennyth | 2021-10-03 19:20