1
\$\begingroup\$

Basically title. Let's say, for example, I walk into Room, and Event A happens. Next time I enter Room A, Event B happens, because Event A already happened. I don't actually want to save this information to a file, at least not for now. I only want a way to keep track of it at runtime.

I suppose a system like this one should be 'engine-agnostic', but just to give some more context, I'm working with Godot 3.5.2 MONO version (C#).

Right now, what I imagine I could do, it's an autoload (persistent) scene that listens and saves every event-action (that is, only the events that could trigger more events) in an array. We can later check if that specific event-action already happened by looking at the array (if it's there, it happened). But I think this only works with a single event (unless that single event is actually a holder for many other events). I'm thinking of something like this:

enter image description here

Buuuut maybe there's an easier way? Maybe there's ANOTHER way?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ While this can be engine agnostic, each engine typically has its own most convenient ways to achieve this (for instance, in RPG Maker, it's built right into the event UI). I think you'll get better answers that are easier to apply in Godot if you tag your question with your Godot version. We already have parallel Q&A for solving similar problems in Unity, etc. \$\endgroup\$ Commented Jun 20, 2023 at 11:43
  • \$\begingroup\$ @DMGregory Done, I'm working with Godot 3.5.2 \$\endgroup\$ Commented Jun 20, 2023 at 22:04

1 Answer 1

2
\$\begingroup\$

Using an autoload

what I imagine I could do, it's an autoload (persistent) scene that listens and saves every event-action (that is, only the events that could trigger more events) in an array.

Yes, something like this is what I've been advocating (e.g. here, here and here).

You can have an autoload with whatever properties you want. There you can define setters to also emit signals.

Then when something loads it can read the properties from the autoload and change to reflect their current value, and also subscribe to the signals so they can react in real time. This way it does not matter if the change happened in the same scene or another, it works.

Plus, having everything in the same place also makes it easy to save it and load it (for the save game feature).


However, I'm also aware that as your game becomes large the autoload also grows and can become hard to manage.

Something you could do is have a dictionary in the autoload, then there would be no need to add more variables to it, instead associate keys for different parts of the code. And you can nest dictionaries!

For example, each scene could save a nested dictionary to a different key of the autoload dictionary, and then different nodes in the scene might save to different keys of that nested dictionary. I hope that makes sense.

An bonus trick is to use get_indexed and set_indexed of the autoload to access the dictionary.

Note: By using dictionaries in Godot we lose type safety, since Godot does not support specifying the type of the keys and values, instead it always works with Variant.


Using Resources

There is another solution if you prefer something more decentralized: Resources.

The idea is that everywhere you preload (not load) a Resource you are going to get the same instance, also anywhere you load it from the inspector you are going to get the same instance.

So make custom Resource types with the fields you need (and you can have signals there too), you create resource files of that custom Resource, and preload them. Any changes to the values of those fields will survive changes of scene.

This is resource based communication (I have an example here).

Plus, being Resources you can save them and load them with ResourceLoader and ResourceSaver.

This approach also means that an scene with the resources it uses can be self-contained (not requiring an autoload or anything external to work).


Now, there is a reason why this is not what I recommend: Godot does not check what it is loading. On one hand this is a way you can have some malicious code injected in the game... On the other this is a way you can provide modding support. Thus, this is not an entry level approach.

The following is what I had to do to make this both safe and easy to use:

Have a custom ResourceFormatLoader and ResourceFormatSaver that saves the Resources in a custom format, that:

  • Does not save specific types (e.g. do not save Scripts). Please note this is not just checking the type of the Resources, instead we traverse the object graph of everything it references, saving item by item, but skipping the undesired types.
  • And does not load them either. Which means it has to load value by value. Which is the reason you cannot use the default format that Godot uses (which would have you load everything as a single unit without checking).

Plus I use code generation (a tool script creating script files) for the boilerplate code of ResourceLoader and ResourceSaver - What boilerplate code?

Well, when it comes to how we use Resources there are three cases:

  • Resources that I just load. Nothing special about these.
  • Resource that I load and I might want to save (mostly used for save games). In this case I want to load from an user:// path if it exists, if it does not I want to load from the res:// path. But I will only save to the user:// path, because the the res:// path is read only on release... So I need to load from the res:// path and change the save path to the user:// path.
  • Resources that I load and I want to save any time they change (mostly used for configuration and unlockable content). They do all the above, plus I also want to subscribe to the changed signal of the Resource and save them automatically.

I have no plans of releasing this at the time of writing.


Something else

Being speculative, perhaps something in the middle would be interesting, for example using code generation to create autoloads. But hat is an avenue I have not explored.

You might also use some database system with Godot. For example, there are modules for SQlite which might work for you.

Similarly, there is interest in including some kind of key-value storage solution in Godot that would replace the need of making the autoloads... But that would be for Godot 4.2 or later.

By the way, you might want to Change scenes manually. This would allow you have scene transitions, loading screens where you use background interactive loading, or - yes - keep things around from one scene to the other.

\$\endgroup\$
3
  • \$\begingroup\$ Huh...didn't think about Dictionaries. Forgot to mention something REALLY important: I'm using the Mono version of Godot so the 'preload' method is not available to use, since it's a GDScript exclusive feature. Also, I'm using a Signal Bus! I'm pretty much already handling the entire game this way, that's why I thought about an autoload scene for this lol. I'm trying to do what I did back in Unity here. The game is pretty simple, and it's HTML5, so I don't need to save anything. I think I'll go with the dictionary approach, sounds cooler hehe. \$\endgroup\$ Commented Jun 21, 2023 at 0:05
  • \$\begingroup\$ Thanks for your answer, and all of your examples, btw \$\endgroup\$ Commented Jun 21, 2023 at 0:07
  • 1
    \$\begingroup\$ @C.G.Yeudiel By the way, the equivalent of preload for C# would be creating and sharing an instance of ResourcePreloader (everybody must be using the same ResourcePreloader), you can load Resources and add them to it, and that way everybody gets the same Resource instances. \$\endgroup\$ Commented Jun 21, 2023 at 0:09

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.