Why is triggering a method in one child of a node triggers the same method to all of the children of the node?

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

Hi! I’m trying to create a topdown shooter zombie game. In my World (main) scene, I have created several nodes like “Survivors”, “Bullets”, and “Enemies” where I would add my zombie scenes as a child of the Enemies node in the ready function. The Zombie scene has a detection radius set to 150 and I want it so that if the player enters this radius, the zombie would start going towards the player and its detection radius would increase to 300. But the problem is, when I spawn some zombies, and I enter the radius of one zombie, all of them would increase their radius to 300 even though I didn’t enter the detection radius of the others. This is the code in my world scene:

onready var Zombie = preload("res://Scenes/Zombie.tscn")

func _ready():
           randomize()
           spawn_zombie(5)

func spawn_zombie(num):
           for i in range(num):
                   var Z = Zombie.instance()
                   $Enemies.add_child(Z)
                   Z.global_position = Vector2(rand_range(300, 600), rand_range(300, 600))

And this is my script in my zombie scene: (However I will not include the part where the zombie goes towards the player because I have no problem with that.)

func _physics_process(delta):
         has_target(delta)

func has_target(delta):
         if target: #target is whoever entered the DetectionRadius
                  $DetectionRadius/Radius.get_shape().set_radius(300)
         else:
                  $DetectionRadius/Radius.get_shape().set_radius(150)

What I have tried so far is that I made a function called “target_seen” in the zombie scene and I placed the expansion of the radius of DetectionRadius code there only to see the same result. I’m a beginner in Godot and I started learning last 3 weeks and this is my first time asking in the site. Thank you!

hi,
With your explanation, i think it should work as you initially intended. Because $DetectionRadius is child of Zombie and each instance of Zombie should have its own DetectionRadius. However, i don’t understand when you set target variable, nor why you pass delta to has_target. Could you, if not the full project, share the code where target is set to true or false? Also the tree structure, and what kind of node are each one?

If you share me the full project i can review it and try to solve it.

p7f | 2019-01-13 14:22

Yes that’s what I thought too! I thought that each child of a node when added via script, would have the same scripts but independent of one another.

This is a shortened version of the code:

Extends KinematicBody2D

var target = null

on_Detection_Radius_body_entered(body):
           if body.name == "Player":
                 target = body
            #I've also tried putting here the expansion of radius, but to only see the same result.

on_Detection_Radius_body_exited(body):
          if  body = target:
               target = null

So if there is a target, we tell that to the has_target(delta). That’s why I have

if target:

in there. It only runs if there is a target. Also, I passed delta in there because if it detects a target, then the zombie would have to move_and_collide(direction_to_player * speed * delta). It would not work without delta. And also, I want the zombies to slowly turn towards the player when it detects the player so I used linear_interpolate from its current direction, to the player’s direction, then I multiplied it to delta. Without delta the zombie would still turn but it looks like its vibrating when it does like when you hit a bell and it makes this ringing sound because of its vibration?

This part of the code is very similar to KidsCanCode’s code on his top down tank battle tutorial. I’m not here to endorse him or anything but that’s where I got the idea from. I learned a lot from him.

bodicpen | 2019-01-13 15:39

Hi,
I’ve done some tests myself and indeed each instanced node has it owns properties. I made a sprite scale when some area enters it and isntanced multiple times and works as expected. Could you share the project for me to see where the problem is?

p7f | 2019-01-13 16:40

:bust_in_silhouette: Reply From: fpicoral

Since all your zombies are using the same scene, when you change a propertie, in this case, the radius, it changes for all of them.
The only thing that I can think right know would be copying zombie to the scene itself, abandon the spawn_zombie() and check individually if the zombie has a target

That would be a little tedious, no? Specially because I’m planning to make this game a bit of an open world where zombies would spawn in random locations at certain times and I don’t want one zombie to affect all of them or else if one sees me then the others will see me too which is might not be a bad thing, actually. However, I’ve figured out a way to make what i want happen. See my answer! :slight_smile: Thank you for answering!

bodicpen | 2019-01-13 13:51

:bust_in_silhouette: Reply From: bodicpen

Okay guys I’ve figured out a way on how to do this. This may not be how it’s done but hey, it works.

What I did is that on the Area2D node which is named “Detection_Radius”,

instead of placing only one collision shape for detection and then increasing it on script when the player enters it, I’ve placed two collision shapes. One collision shape is named “detected” (300 radius) and one is “undetected” (150 radius). I have disabled the “detected” collision shape by default. And now, when the player enters the detection_radius, the “detected” collision shape will now be enabled. Like this:

func _on_Detection_Radius_body_entered(body):
          $Detection_Radius/detected.disabled = false
           #this will then increase the radius of the Area2D

func _on_Detection_Radius_body_exited(body):
          $Detection_Radius/detected.disabled = true
          #this will then disable it, making the radius of the Area2D back to its original value.

And when I’ve tried it, it works. The detection radius of other zombies is not affected anymore by any one of them. Of course, this may work for now, but I still want to know if there’s another way to do it.

I’ve just seen your answer. Have you tried directly setting the radius in the functions _on_Detection_Radius_body_entered(body) and _on_Detection_Radius_body_exited(body) intead of enabling and disabling radius there?

p7f | 2019-01-13 14:25

Hello. Yes I’ve tried it. After I’ve made the “target_seen” function, I’ve placed the expansion of the detection radius there to call it into the process but then I got the same result. Then I thought, I’m just doing the same thing. I just placed the expansion of the radius in a different function only to call it to the process which may explain why I got the same result.

Then I placed that expansion code to the _on_Detection_Radius_body_entered(body) and _on_Detection_Radius_body_exited(body) but same result, all of them were affected as if I entered all of their radius.

For now, my answer is the only way I’ve found to make it work. Initially, I thought that if you add a scene to a child of a node, each of them would have the same but independent scripts but it looks like thats not the case, maybe.

bodicpen | 2019-01-13 15:31