Add specific instance of scene to an array

Godot Version

4.2.1

Question

So, I have this simple scene setup. It was made for debugging only:

screenshot-1718495715885

What I am trying to do is, as the title says, add only one of the child nodes shown to an array. I’ve made it so both FirstBody and SecondBody are next to each other like this:

next

Only the SecondBody, which has the raycast not interacting with anything, should be added to the array. Yet both of them appear in there. Here is the code for first and second body, which are just instances of the scene which has this script attached. I know I am adding only the name, not the reference to the instance itself, but the behaviour is the same. dataManage is just an autoload which initializes the string array:

using Godot;
using System;

public partial class character_body_2d : CharacterBody2D
{
    RayCast2D ray;
    bool added = false;

    public override void _Ready()
    {
        base._Ready();
        ray = GetNode<RayCast2D>("RayCast2D");
    }

    public override void _PhysicsProcess(double delta)
    {
        if (!ray.IsColliding()) {
            GD.Print($"The one that isn't colliding is {Name}");
            Modulate = Colors.Green;
            if (!added) {
                added = true;
                dataManage.Things.Add(Name);
            }
        }

        else {
            Modulate = Colors.Red;
            GD.Print($"The one that IS colliding is {this.Name}");
        }
        Velocity = new Vector2(0, 1) * 10;
        MoveAndSlide();
    }
}

unless you have reason to do otherwise i would use a list

node tree:

Untitled

using Godot;
using System.Collections.Generic;
public partial class MyCsharp:Node2D {
	List<Node2D> m_list_node = new List<Node2D>();
	public override void _Ready() {
		Node2D v_node_a = GetNode<Node2D>("A");
		Node2D v_node_b = GetNode<Node2D>("B");
		Node2D v_node_c = GetNode<Node2D>("C");

		m_list_node.Add(v_node_a);
		m_list_node.Add(v_node_b);
		m_list_node.Add(v_node_c); // add A B C

		GD.Print("expected: A B C");
		foreach(Node2D j_node in m_list_node) {
			GD.Print(j_node.Name);
		}

		m_list_node.Remove(GetNode<Node2D>("C")); // remove C

		GD.Print("expected: A B");
		foreach(Node2D j_node in m_list_node) {
			GD.Print(j_node.Name);
		}

		m_list_node.Remove(v_node_b); // remove B

		GD.Print("expected: A);
		foreach(Node2D j_node in m_list_node) {
			GD.Print(j_node.Name);
		}
	}
}

I am applying the same code I made in a larger project which has a dynamic size of enemies. The idea was to send a signal every time an event happened and have an array of specific enemy instances so I can manage them quickly

never tried groups but groups might be what you are looking for

Also if interested below are a couple examples of signals in c#

c# signal example copypaste
using Godot;
using System;
public partial class MyTimer:Timer {

	public Action m_timeout_func = null;

	void DoTimeout() {
		GD.Print("normal function");


		Disconnect(Timer.SignalName.Timeout, Callable.From(DoTimeout)); // and how to disconnect the signal
	}

	public override void _Ready() {

		Action m_variable_timeout_function = () => {
			GD.Print("function stored as a variable");
		};

		Start(2); // timer triggers every 2 secs

		// connect timeout signals

		Connect(Timer.SignalName.Timeout, Callable.From(DoTimeout)); // void DoTimeout() {}

		Connect(Timer.SignalName.Timeout, Callable.From(m_variable_timeout_function)); // Action m_timeout_func = () => {}

		Connect(Timer.SignalName.Timeout, Callable.From(() => {
			GD.Print("anonymous function");
		}));

	}
}
c# custom signals
using Godot;
using System;

public partial class MySignal:Node {

	//////////////////////////////////////////////////////////////
	// [Signal] is how we create a signal for Godot in c#   //////
	//////////////////////////////////////////////////////////////

	// please note: delegate must end in --> EventHandler <--

	[Signal]
	public delegate void MyHelloWorldEventHandler(); // SignalName.MyHelloWorld created!

	[Signal]
	public delegate void MyTestEventHandler(); // SignalName.MyTest created!

	///////////////////////////
	// callable functions /////
	///////////////////////////

	// no arguments
	// Callable.From(DoTest)
	void DoTest() {
		GD.Print("############### This is a test ##################");
	}


	// string argument
	// Callable.From<string>(DoHelloWorld)
	void DoHelloWorld(string a_message) { 
		GD.Print(a_message);
	}




	public override void _Ready() {

		//////////////////////////
		// connect signals  //////
		//////////////////////////

		Connect(SignalName.MyTest, Callable.From(DoTest)); // no arguments
		Connect(SignalName.MyHelloWorld, Callable.From<string>(DoHelloWorld)); // string argument

		////////////////////////
		// emit signals ////////
		////////////////////////

		EmitSignal(SignalName.MyHelloWorld, "This is a message from the future");
		EmitSignal(SignalName.MyTest);
	}
}

Thanks, but I’ve tried that too, it didn’t work :(. Same thing happened, with every instance being added to the group. I tinkered with the code for a lotta time and arrived at the conclusion that’s just how groups work. But since the same is happening here, thought the issue might be something else

Im guessing you need to make the raycast unique.

Wdym? I thought only resources could be made unique

Im 99% sure raycasts also collide with the body that sends them, so you have to check if the body colliding is not yourself.

Also, @EvilGenius, you don’t make node’s unique. You can make scenes unique but not nodes

Sorry I can’t help since I don’t know C#

I just checked here and I did enable both “Exclude parent” and “Hit from inside” from the raycast, so unfortunately I don’t think that’s the problem :frowning_with_open_mouth:

Could you show us a video of the bug? Also, maybe add an print to print the bodys the raycast is colliding with and enable seeing raycasts while debugging. These will all help us help you.

1 Like

well, i’ve gone ahead and decided to zip it. i also added the scripts in gdscript, since it’s such a small project. The project already has the debug statements (just a bunch of prints) and the collision shapes visible, so just running it should give enough information. if anyone’s interested on taking a look, there it is. thank you for even reading the post, regardless!

My mistake I thought it was a resource. I’m used to having to make sure my RectangleShape2Ds are unique or else my collision is a mess.

I would check that the RayCast in firstBody is actually hitting something.
Turn on visible collisions, run it and see. (The raycast will turn red)

I trying understand what your propose in this,
There’s prints in your code but you don’t show any logs.
if both object appears in your list that mean all requirements was “true” for any _PhysicsProcess

Only one of the objects should appear in the list, that is the problem. It should be impossible for FirstBody to be in there if its raycast is colliding with something.

and what your logs telling?

that what i expected first frame raycast not colliding he needed more time
obraz
@prynpo
In _Ready disabled _PhysicsProcess and enable with tween after 1 second
that’s allow me wait for raycast be warmup and start. That allow me skip checking is first _PhysicsProcess

    public override void _Ready()
    {
        base._Ready();
        ray = GetNode<RayCast2D>("RayCast2D");
        SetPhysicsProcess(false);
        Tween tween = CreateTween();
        _ = tween.TweenCallback(Callable.From(() => SetPhysicsProcess(true))).SetDelay(1f);
    }

obraz

alternative you make raycast from script not node and get collision from first call.

1 Like

Yeah, you’re right. Instead I removed it from the list in case it’s colliding with something inside the second if statement. Thank you!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.