Godot Version
4.3
I have several Nodes that do not always need to be in the scene tree in my game but they do always need to exist. So I made a NodeManager class to store pointers to each of these scenes and then I instantiate them all 1 time at startup. This approach is recommend in the performance section of the docs so I figure it is something a lot of games must be doing. This is working…during the game I can retrieve these nodes however for some reason if I go to the main menu of my game and then back into the game and then back to the main menu all the pointers just become invalid for seemingly no reason and then cause the game to crash when trying to access them again.
Here is my NodeManager class:
class NodeManager : public RefCounted {
GDCLASS(NodeManager, RefCounted)
GDSINGLETON(NodeManager)
HashMap<StringName, Node *> nodes;
protected:
static void _bind_methods() {
ClassDB::bind_method(D_METHOD("get", "key"), &NodeManager::get);
ClassDB::bind_method(D_METHOD("set", "key", "node"), &NodeManager::set);
ClassDB::bind_method(D_METHOD("remove", "key"), &NodeManager::remove);
ClassDB::bind_method(D_METHOD("has", "key"), &NodeManager::has);
ClassDB::bind_method(D_METHOD("clear"), &NodeManager::clear);
}
public:
Node *get(const String &key) { return nodes[key]; }
void set(const String &key, Node *node) { nodes[key] = node; }
void remove(const String &key) { nodes.erase(key); }
bool has(const String &key) { return nodes.has(key); }
static Node *init_scene(String path) {
Ref<PackedScene> scene = ResourceLoader::get_singleton()->load(path);
if (scene == nullptr) {
UtilityFunctions::printerr("Error initializing: ", path);
return nullptr;
}
return scene->instantiate();
}
void clear() {
for (const KeyValue<StringName, Node *> &key_value : nodes) {
if (key_value.value != nullptr) {
key_value.value->queue_free();
}
}
}
};
Like I said this works perfectly fine, the init() function is only ever called one time at game start so the pointers SHOULD always be valid… I am never calling any kind of free or delete function on them so it seems like somehow the engine is just randomly deciding these pointers don’t need to exist and frees them itself. Am I stupid? How would these pointers possibly get invalidated even though I store references to them and never delete them and also never set them to null?