Multiple instanced bullet nodes reacting to a signal

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

Hi. I have this issue:

-I have one node Area2D emitting the “body_entered” signal
-I have multiple instances of a bullet node which connects to that “body_entered” signal

The problem is that all instanced bullets react to the signal when just only one bullet enters the Area2D, but I want only that single bullet reacting to the signal, not all the bullets.

The fact is that all the bullets share the same script and all call “connect” at the same time.

:bust_in_silhouette: Reply From: TheZioba

Resolved: I make a match on the name of the bullet(body) returned from the signal and the self node.

:bust_in_silhouette: Reply From: Wakatta

Hate to be the bearer of bad news but you solved nothing.
The body_entered signal has a param body that can be compared against self like this if body == self
Your approach is not wrong but it gives the CPU unnecessary work to do.

Let’s say you later add a machine gun to your project that fires 20 bullets per second that would mean if you had multiple onscreen at anytime the signal would be emitted 20 * n machine guns onscreen and then a match statement checked each time.

Once again I say there is nothing wrong with your approach but for efficiency sake consider handling the body_enterd signal in it’s own script

Ok, thank you. Here’s there’s an efficiency problem. So what’s the solution? If I call “connect” in the Area2D script I cannot modify the behaviour of the bullet, because I have all methods and members in the bullet script and most of the time the game crashes when I try to modify the behaviour of a node from the script of another node (I this case I would have to modify the behaviour of the bullet from the script of the Area2D node).

TheZioba | 2021-04-06 09:14

Correct. And the body_entered signal already sends the ‘body’ (bullet) to be modified.
You you can do something like body.queue_free() or use any other methods or variables from your bullet scene/node.

P.s you can change body to any other name (like bullet)

Wakatta | 2021-04-06 10:08

Thank you for replying. I tried this, but the compiler gives me error. I am working with GDNative C++: the problem is that I try to convert body, which is a Node* type into a Bullet* type in order to apply methods to it from the bullet code.

I am trying, the Area2D code, after I called connect in its ready function:

on_body_entered_Bullet_function(Node* body) {
body = (Bullet*) body;
…applying Bullet functions to body…
}

But it doesn’t work.

TheZioba | 2021-04-06 16:17

Ahhh I see. I haven’t used C++ with Godot but with the standard format you’d have to accept the input as is then do a type cast using a different variable.

on_body_entered_Bulletfunction(Node* body) {
    (Bullet*) bullet = (Bullet*) body
}

Or maybe from the get go accept only bullet types in your function

on_body_entered_Bulletfunction(Bullet* bullet) {
    
}

Again, I say I’ve never used C++ with Godot so I don’t know all the conventions.

Wakatta | 2021-04-06 16:27

Thank you again for replying. I think the first of the two is the correct solution, the second one gives a compiler error.

The problem is now that, as I expected, the game crashes because I am trying to apply code of the bullet node from the area2D node.

Now I should do the one-by-one-row-test to see which is the exactly row which makes the game crash, but the editor gives me this error:

ERROR: get: FATAL: Index p_index = 0 is out of bounds (size() = -9765010).
At: ./core/cowdata.h:152

TheZioba | 2021-04-06 17:41

Like I said before nothing was wrong with your initial approach.
It’s just that efficiency wise what actually happens is something you needed to be mindful of. Because as your project grows and your fps drops debugging where that happens becomes and unwanted nightmare. So my apologies for sending you down a seemingly never ending rabbit hole

Wakatta | 2021-04-06 18:02

No problem. thank you for spotting me this issue. The fact is that I want to write efficient code, but without my game crashing.

How could I solve this problem? If I use another script function on “body”, the game crashes. :frowning:

TheZioba | 2021-04-07 14:07

Could you show an example of that happening?
Maybe I can give some insight because that definitely shouldn’t be the case

Wakatta | 2021-04-07 23:45

So I try to explain this as simply as possible.
The Bullet script has a string member variable “last player”, with setter and getter functions, which tracks who shot that bullet.

In the Bullet script I call “connect” on player and opponent nodes to listen to the labeling signal, emitted by the player or the opponent when they shoot the bullet, with the string “Player” or “Opponent”, depending on the shooter of the bullet.

I want the Area2D node to make the bullet react to the “body entered” signal, so in the Area2D script, inside the _ready() function, I call connect on “this” node and I pass the reacting_function:

void reactingfunction(Node* body) {
Bullet* bullet = (Bullet*) body; //this is ok
Godot::print(bullet->get_last_player());
}
“get_last_player()” makes my game crash when the “body_entered” signal is triggered, because it is written in the Area2D script, not in the Bullet script: I’m trying to access a member variable via getter through another script.

TheZioba | 2021-04-08 11:08

Which is a legal move and should not cause that crash.

If the player/opponent has their own script that will also be a nice place to put the area2d connect and react code.

What do you get if you try to print body? Or another member of body like body.get_class()

Also your workflow is well laid out and detailed nice.

Wakatta | 2021-04-10 01:11

You’re making me want to learn Godot C++
Since I know how both work already but just getting started got any pointers for me? Lol

Wakatta | 2021-04-10 01:15

So this is what I tried so far, inside the reactingfunction, in the Area2D script, after
(Bullet*) bullet = (Bullet*) body;

print(body->get_name()); //this is ok, prints Bullet on screen
print(bullet->get_name()); // this is ok, prints Bullet on screen

print(body->get_class()); //this is also ok, prints KinamticBody2D on screen
print(bullet->get_class()); //this is ok, prints KinematicBody2D on screen

Problems start when I use functions defined in the Bullet script.
For example, beside the crash I alreay explained, if I write:

print(bullet->get_speed()) //this works, but gives me wrong values for the variable speed, defined in the bullet script, on screen:
speed is fixed at 600.0, but the function returns me sometimes 0, sometimes 359.144.

I really don’t know why. I tried to register_method on
get_speed() and set_speed(float b_speed), but it doesn’t work anyway.

UPDATE: the code translated in gdscript works: I can manipulate the bullet from the area2D script using “body_entered” in the area2D script.
This is a GDNative issue.

UPDATE: I think here the problem is the pointer. I am not confidential with how pointers work in godot, but maybe I should use Ref<> operator somehow, instead of * for the bullet variable.

TheZioba | 2021-04-10 16:36

RESOLVED: I really, really don’t know why, but this is what I have in the Area2D script:

Bullet* bullet = (Bullet*) body; //this makes the game crash and returns wrong property values when accessing bullet functions

instead

Bullet* bullet = Object::cast_to< Bullet>(body); //this makes everything work fine, both property access and function usage, without crash

Could someone explain me why?
I wonder which syntax to use depending on the situation.

TheZioba | 2021-04-11 17:48

Ahahahahahaha look at you. While you’re solving problems I’m having alot of em trying to set up mono with C#. I recommend you start a new question for the syntax situation

Wakatta | 2021-04-11 20:54