Access to the properties of the Node using GetNode (Godot 4, C#)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By slavi

I have a script “UniversalBehavior” with universal behavior that fits different nodes, in my case I used “Sprite3D” and “MeshInstance3D”. To be able to attach this script to both types, I used my class’s inheritance from “Node”. (this is the common ancestor of both types)

public partial class UniversalBehavior : Node
{
	public override void _Process(double delta)
	{
		//Do something universal for different types of nodes
	}
}

There is another script “OtherScript” that I created for demonstration purposes. To simplify, it works directly with the “Sprite3D” node that is in the scene.

public partial class OtherScript : Node
{
	[Export] Texture2D tex1, tex2;
	Sprite3D spriteNode;
	int a;
	public override void _Ready()
	{
		spriteNode = GetNode("/root/Node3D/Sprite3D") as Sprite3D;
		GD.Print(spriteNode.GetType());
	}

	public override void _Process(double delta)
	{
		a++;
		if(a%200 > 100) spriteNode.Texture = tex1; 
		else spriteNode.Texture = tex2;
	}
}

The “OtherScript” script only works correctly if “UniversalBehavior” inherits from “Sprite3D”, but then “UniversalBehavior” cannot be attached to other types of nodes. (in my case to “MeshInstance3D”)

The problem is that I can’t access the fields of the “Sprite3D” node, because it has a script attached to it that inherits from “Node”. But the fact that these fields still exist is undeniable, I can change them in the Inspector. (and I want to understand how to do it through the code)

The string “GD.Print(spriteNode.GetType());” says that the received node is of type “UniversalBehavior” and not “Sprite3D”, but I want to have access to the node itself and not to the script that is connected to it.
Is this the correct behavior of the GetNode() method?

How to access “Sprite3D” fields from “OtherScript” script?
(and don’t change “UniversalBehavior : Node” to “UniversalBehavior : Sprite3D”)

:bust_in_silhouette: Reply From: Phosphor

You could try using an interface and use proper inheritance, by having the class inherit from node, the object in Net will only have those properties that belong to the base class, in this case node.

So as first mentioned you could try an interface.

public interface UniversalBehavoir
{
    public virtual void DoSomethingUniversal()
    {
        GD.Print("Did something universal");
    }
}

Note the method is declared virtual so it can be overridden if desired. Then your Sprite3D class might look like:

public partial class SomeSprite : Sprite3D, UniversalBehavoir
{
	public override void _Ready()
	{
		UniversalBehavoir ub = this;
		ub.DoSomethingUniversal();
	}
}

And your mesh like this:

public partial class SomeMesh : MeshInstance3D, UniversalBehavoir
{
	public override void _Ready()
	{
		UniversalBehavoir ub = this;
		ub.DoSomethingUniversal();
	}
	
}

Hopefully this helps.

Thanks for the answer, but this doesn’t scale well, if hypothetically I have 50 different types then I would have to create 50 separate scripts

I suspect that accessing the fields is somehow easier, it’s just not obvious

slavi | 2023-03-27 02:36

:bust_in_silhouette: Reply From: Moreus

There is GetClass() but return string instead object, and IsClass and this return bool as suspected… but i dint find anyway to access them.
Only solution what i can give you now is make your make your class Child of target and get parent
var sprite = GetParentOrNull<Sprite3D>();
or opposite and get child