Hi there!
I want to have a door that only opens when you have defeated a list of enemies before it. I would like the door to have a list or array of the enemies that need to be defeated.
In my head, I should be able to declare an array for the door scene, and then have an array of some type like “Node3D” or “StaticBody3D” and drag/drop the enemies I have placed in the level within the editor. But I can’t seem to either get the type right or figure out how to make this array accept the scenes I have instantiated into the level.
How can I do this?
Thanks for any help! I provided a screenshot to illustrate further what I am trying to accomplish/
@export_node_path("StaticBody3D") var enemy_array: Array[NodePath]
However, keep in mind a parent node is only ready when all of it’s children are ready. If your node is referencing a lot of parent or sibling nodes, some of them will not be ready, you may have to wait a frame await get_tree().process_frame or get the nodes as they are needed.
Okay, I think this ended up being an issue with signals. I was able to add some objects to the array in the editor using the @export variable.
Here is the gist:
My BaseDoor.tscn holds an Array of Node3D, which I add to from the viewport in the editor. Then, in the _ready function, I loop through the list and connect to a signal on the enemy nodes I added to the array. That signal goes off if an enemy is destroyed:
extends StaticBody3D
class_name BaseDoor
@export var enemy_array : Array[Node3D] = []
func _ready():
for enemy in enemy_array:
assert(enemy is Seeker || enemy is Tower)
if enemy is Seeker:
enemy._alert_parent_door_node.connect(_remove_enemy_from_array)
func _remove_enemy_from_array(enemy : Node3D):
print("ERASING!")
enemy_array.erase(enemy)
if enemy_array.is_empty():
_open_door()
func _open_door():
# TODO: I should animate this
queue_free()
I am still unsure why I was unable to act upon the Nodes I added from the editor. For what it’s worth, I was adding them into the scene using this button here (The instantiate child button):
Noted - thank you for the tip about waiting a frame to get the nodes.
I made it work using an Array of Node3D (wasn’t sure how else to group different variants of enemies that have different class names), which is going to force me to require some type checking.
Keeping in mind that the enemies are not children of the object referencing them in a member array (the door scene), are you saying that it would be better to have it be an array of NodePaths, since it is more efficient/flexible?
Also, perhaps I misunderstood but I have a GD script error using that line of code
res://Scripts/BaseDoor.gd:5 - Parse Error: "@export_node_path" annotation requires a variable of type "NodePath" but type "Array[NodePath]" was given instead.
NodePath would work better within the engine. All scene files and exports use and save as NodePath under the hood, I remember bugs with using nodes directly in non-scene tree objects like resources, so I recommend against nodes directly as an export.
I believe the nitty gritty is that @export uses get_node on the script, but your resource doesn’t have get_node, as it’s not a Node object itself, so it will fail. Instead you need to pass a Node into what ever resource function you want to use and call get_node on that with the appropriate path.
Writing that out I’ve noticed your door script which is exporting is a Node type, not a Resource so the NodePath thing might be unecessary; I must’ve been tripped up by the Seeker icon, it shows a resource icon instead of the CharacterBody3D icon. Sorry about the round trip
All good - thank you for the context anyways, I am really happy to learn something. If anything, this is a good reminder for me to read up about resources again. Thanks again for the help!