Access Subscene methods

Godot Version

v4.2.2

Question

this is probably quite a beginner’s question, but the posts I’ve found don’t quite help. I guess I just have the wrong “mental model” of how things should work.
The following situation, I have a tree that looks like this:

-root (root.tscn)
–arena (node with attached script arena.gd)
—player (player.tscn)
—enemy (enemy.tscn)
—enemy (enemy.tscn)

player and enemy scenes look like this:
-Node2D (Attached script player.gd or enemy.gd)
–sprite2d
–…

Within arena.gd I get the child nodes with get_children (the instances of player.tscn and enemy.tscn). However, these nodes are of type Node2d. So I cannot access my methods.

So my question is:
What ways are there to access the methods of the attached scripts player.gd and enemy.gd without having to explicitly list the instances somewhere? Of course I could use signals, but as I understand it so far, I would have to explicitly call the instances of player and enemies in arena to connect the signals. That’s why I wanted to use the get_children approach, as I wouldn’t have to explicitly name the children here.

I found out for myself. Calling methods from subscenes works… The top node must also have the script attached in the subscene. I don’t know why they weren’t for me, because normally this happens automatically. So the tree should look like this:

-root (root.tscn)
-arena (node with attached script arena.gd)
-player (player.tscn with attached script player.gd)
-enemy (enemy.tscn with attached script enemy.gd)
-enemy (enemy.tscn with attached script enemy.gd)

player and enemy scenes look like this:
-Node2D (Attached script player.gd or enemy.gd)
-sprite2d
-…

  • Create a script for your player or enemy
  • on the first line, you can write class_name Player or class_name Enemy
  • inside your arena.gd, you can then initialize the child nodes as @export var player: Player and then assign the player scene to arena
  • your player node will now autocorrect all its specifically created methods

as script are usually attached to the scene, you can not just execute a method without having a reference of the scene, that’s why your solution is also dependent on get_children(). If your method functionality is general, you can create an autoload variable (maybe call it Global.gd) and then you can access Global.do_something() anywhere you want.

For example, Global.do_something(child) can be called regardless if child is an enemy or player. Useful for something like Global.highlight_character(node). You can also employ other solution that makes use of a Base_Unit class, which your Player and Enemy are inheriting from. That way, both share the same base methods that can be called by your arena.gd.
Example for Base_Class that has update_health() for Player+Enemy:

for child in get_children():
   if child.has_method("update_health"):
      child.update_health()

Lastly, when you instantiate player and enemy on run-time, you can then add them to specific groups. Afterwards, you are then able to loop through the group and then execute specific instructions/methods. That way, you don’t require a “hook” on the object or a variable, and you don’t require get_children() although it is quite similar in effect.