Attention | Topic was automatically imported from the old Question2Answer platform. | |
Asked By | plaw |
I’m not sure if it’s a bug in Godot, a fault on my part, or a misunderstanding on how exactly signals work. So I decided to post my problem here.
I have the following situation:
I have an ‘enemy’ scene which consists of a parent node (type: KinematicBody
) to which an Area
is attached as a child. In the script of the Area
I connect both body_shape_entered
and body_shape_exited
signals to appropriate receiver methods. whenever somethind enters or leaves the area, it’s been kept track of in an _area_cintents
array. Once the damage area’s big moment has come, the AI calls a do_damage()
method which inflicts damage upon all nodes within the area.
Here’s the simplified code:
var _area_contents : Array
func _ready():
_area_contents = []
connect("body_shape_entered", self, "_on_body_shape_entered")
connect("body_shape_exited", self, "_on_body_shape_exited")
func _on_body_shape_entered(_body_id, _body, _body_shape, _area_shape):
_area_contents.push_back(_body)
func _on_body_shape_exited(_body_id, _body, _body_shape, _area_shape):
var index = _area_contents.find(_body)
if index >= 0:
_area_contents.remove(index)
func do_damage():
for target in _area_contents:
if target is Damageable:
target.hurt()
The enemy is controlled by a small state machine which calls do_damage()
from the outside if the curcumstances are right.
This works pretty well as long as there is only one instance of the ‘enemy’ scene in my level. Once I spawn multiple instances, I observed the following behaviour once I digged deeper using the debugger:
The functions _on_body_shape_entered
and _on_body_shape_exited
are called properly and within their scope _area_contents
contains the expected nodes.
However, whendo_damage()
is called on the same entity _area_contents
is shown to be empty in the debugger and the function has no effect. _area_contents
isn’t accessed anywhere else, only in those three functions in the Area
node script.
I’m currently using Godot 3.2.2 stable.
Is this intended behaviour and I’m missing something? Or could this be a problem in Godot? Any hint on what the cause of this might be would be deeply appreciated.
Seems good to me. Are your absolutly sure that do_damage() is called on the right entity?
Have you tracked it with breakpoints?
klaas | 2020-07-17 17:14
could you be calling do_damage before _ready is called? for example in an _init or from a _ready in a parent perhaps for testing idk
you could test this by putting your _ready code in _init and see if fixed i think
rakkarage | 2020-07-17 17:45
since _init is called on construct and before the object and there children enter the tree that would make no sense.
klaas | 2020-07-17 17:53
I’ve found a workaround. Yet, I do not understand why I was observing this behaviour previously. Here’s what I changed:
The Area
node, being a child of an ‘enemy’ node, has to be referenced in the ‘enemy’ node’s script, so the AI can call do_damage
when the enemy attacks. I’ve applied a somewhat unnecessary pattern (a non-pattern if you will) to get the reference to the area:
export (NodePath) var DamageAreaPath
var damage_area
func initialize():
if has_node(DamageAreaPath)
damage_area = get_node(DamageAreaPath)
# later...
func attack():
damage_area.do_damage()
Changing the initialize
function to this, fixed the issue:
func initialize():
if has_node("DamageArea"):
attack_area = $DamageArea
The project is much more complex by now and I don’t know what contributed to the problem. I tried to reproduce the wrong behaviour in a simplified test project but both of the above cases work as you would expect them to.
I would file this under human error and consider this issue resolved.
Thanks to everyone who took a look.
plaw | 2020-07-17 20:17