#Instancing and Accessing Other Nodes' Methods and Attributes

5 messages · Page 1 of 1 (latest)

oak remnant
#

Hi, I'd like a better understanding of how I can communicate and call functions between nodes. This is something I'd like to broadly get a better understanding of, but using an example will help.

In my case, I'm trying to create a modular system for handling attacks. The player can have one of many attacks from a list, and the enemies can also use all these same attacks. So I have a scene for my Player and a scene for my Enemy, as well as a third scene for my Attack.

What I'm trying to do is use the Attack.tscn as a go-between, it should be able to take in the player character's attributes (as defined in the Player.cs script) and use them in a separate damage calculation method which would be called by the Enemy.cs when the attack enters its hurtbox. The Enemy has a signal set for when something enters its hurtbox area, and it's validated as something that's meant to hit it as it checks that the intersecting area has a DamageEnemy() method, but from here I'm not sure how to call it.

My enemy code is as follows:

int HP = 20;

    private void On_hurtbox_area_entered(Area3D body)
    {
        if (body.HasMethod("DamageEnemy"))
        {
            HP = HP - body.DamageEnemy();
            if (HP <= 0)
            {
                OnDeath();
            }
        }

    }```

``body.DamageEnemy()``  is not syntax vs. code likes because it doesn't know what it's looking for without the actual input and that has me unsure if this is a "proper" way of going about things.

As for the ``Player`` scene, the idea is that you can have different attacks assigned and they're not always needed so they're added as child nodes when needed

```C#
public override void _Ready()
    {
        base._Ready();
        animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
        var attack1 = GD.Load<PackedScene>("res://mov/" + playerAttack1 + ".tscn");
        AddChild(attack1.Instantiate());
        attack1.name = "Attack1";
        if (playerAttack2 == null)
        {

        }
        else
        {
            var attack2 = GD.Load<PackedScene>("res://mov/" + playerAttack2 + ".tscn");
            AddChild(attack2.Instantiate());
        }
        
        
    }```

Here I'm trying to be clever and feeding in ``playerAttack2`` strings to load only the relevant attacks. The issue there is I'm not sure how to then appropriately reference the newly introduced node. The line ``attack1.name = "Attack1"`` (these names could probably use some tweaking) is an attempt to then name the node to be referenced (so for example when used I could call ``Attack1.GetStats()``) but as I understand that isn't actually referencing the newly instanced scene and name isn't a valid attribute. I'm unsure how to get these things communicating the way I need to, and I imagine this sort of thing comes up a lot in Godot.

Tiny extra thing is that a particular desired effect of this attack in question is an effect of dashing forward, should I be able to affect the attributes of the parent node (this being the ``Player``) from within the ``Attack.cs`` methods? I'm aware Godot has built in methods like ``GetParent()`` that should help here, but in seeking answers I saw claims this would be bad practice. My apologies if this is too basic a question or too wordy, I've just struggled to quite wrap my head around this today.
thorny hinge
#

re: apologies: no, you're doing fine. I am not sure what you are confused about though. AFAICT the question is "I'm not sure how to then appropriately reference the newly introduced node".
You're creating it AddChild(attack1.Instantiate()); -- you immediately add it as a child

#

but if you want to hold a reference to it, I suggest just holding a reference to it! My C# is rusty, forgive me, but it's just a variable:

Node newAttack = attack1.Instantiate();
AddChild(newAttack);
doSomethingWithAttack(newAttack);
#

By construction you (the programmer) know that all of these scenes are going to implement your AttackNode script, so you could also downcast it now:

AttackNode newAttack = (AttackNode)attack1.Instantiate();

(ohgod I don't remember C# pretend that's accurate syntax... edit: looked it up. It is! I rule!)

anyway, the downcast is necessary because without that you can't access any of its fields. And you can be safer about this sort of thing as well, making a check that the instantiated scene really is the correct kind of AttackNode.