Hello Godots,

Okay, so I'm about to but the final touch on my first ever Godot game. A simple 2D top downer. Anyway!

So, in this game I have a Player-scene from which I can queue_free() some enemy spawnPoints objects in the game.

The very same spawnPoints are used in my GameScene-scene where a function is spawning enemies from those spawnPoints. I've made an @export array and added the spawnPoints manually from the Inspector. During a game, every 10th second an enemy is spawned from one of these spawnPoints via a timer (they are spawned from the GameScene-script).

So - during a game session, some of these, if not all, spawnPoints are removed as part of completion of a level. However, as soon as the GameScene-script is trying to add an enemy from a previously freed spawnPoint the game crashes, obviously.

I cannot wrap my head around how to fix this. I thought maybe when I queue_freed() a node it was also removed from any arrays it might had been in, but this does not seem to be the case.

Can anybody point me in the right direction here? 🙂

Thank you in advance!

All the best,
theloneswiftman

    theloneswiftman You can't store nodes in arrays. You can only store references to nodes. So that's what your array contains - references to nodes. However when a node gets freed, any existing references to it will become invalid so you need to take care to eliminate those references too, or at least not to use them any more.

    For the thing you described you don't need to store anything into any arrays though. Simply assign nodes into the same scene tree group. That way when a node is freed it will also be removed from the group.

    I think you need to keep track of which array(s) a spawnPoint is added to, so that you can manually remove it when you queue-free it.

    If there are multiple arrays, the spawnPoint's metadata could be a convenient place for storing that information. See the *_meta methods here:
    https://docs.godotengine.org/en/4.1/classes/class_object.html#class-object

    Another way is to use is_instance_valid() on the spawnPoint before trying to use it to add an enemy.
    https://docs.godotengine.org/en/4.1/classes/class_@globalscope.html#class-globalscope-method-is-instance-valid

    Another approach is to use groups to keep track of the spawnPoints. I don't know enough about your project to tell whether that's feasible.
    https://docs.godotengine.org/en/4.1/classes/class_node.html#class-node-method-add-to-group

    (I see that xyz beat me to replying. But my answer is probably better. 😉)

    • xyz replied to this.

      DaveTheCoder (I see that xyz beat me to replying. But my answer is probably better. 😉)

      If by better you mean complicated-er, then yes 😛

      Almost makes me wonder if it might make sense to have something similar to init() but for freeing nodes. So if you queue free it first goes through the cleanup including things you have manually specified before it actually calls free()... nah crazy talk.

      • Toxe replied to this.

        Megalomaniak That would be nice indeed. But at least you can listen for the PREDELETE notification.

        theloneswiftman When do stuff similar to what you're doing, I usually create generalistic functions so that I just have to call the corresponding add() and remove() functions and all the additional functionality is handled there. For example, you can create these 2 functions:

        • add_spawn_point(whatever arguments you need): This function instantiates the spawnPoint, adds it to the scene and inserts it into the array. You can also use it for any other additional operations you may need, like initializing the spawn point with the types of enemies it has to create.
        • remove_spawn_point(spawn_point: SpawnPoint): This removes the spawn_point from the array and then deletes it with spawn_point.queue_free(). You can also use this to trigger an explosion or whatever.

        The cleanest way would be to have the spawn_point nodes trigger a "spawn_point_destroyed" signal when their HP reaches 0 and have your GameScene script listen to it. When the signal is activated, the remove_spawn-point() function in the GameScene script is called.

        Try to centralize functionality as much as you can: In this case the player really doesn't need to know about the spawnPoint array, so just make it launch a signal and let the GameScene script deal with everything related to the array and the spawn points.

        Just use a group. It'll likely solve your problem. I'm repeating it because it may get lost in the noise of other more complicated suggestions.

        Thank you each and everyone! After reading all of the inputs and trying them out I went with @xyz's suggestion with groups. It's simple and works like a charm! 🙂

        Have a lovely weekend ahead!