Reputation: 26
When i go through every "Black_Hole's" only one is shrinking (that 1st. one)
Explanation image:
Accordings to the comments - Script of "Black_Hole":
extends Spatial
var animation_finished
var scale_down_black_hole
var animation_played
onready var namex = get_name()
onready var group_holes = get_node("Group_Holes")
var group_black_holes = group_holes.get_child()
func _ready():
animation_finished = false
scale_down_black_hole = false
animation_played = false
# print(get_name())
print(group_black_holes)
$AnimationPlayer.stop(true)
# $AnimationPlayer.stop("Animation_Black_Hole") #kod pauzuja̧cy animacjȩ
# $AnimationPlayer.play("Animation_Black_Hole") #kod wznawiaja̧cy animacjȩ
pass
func _process(delta):
if scale_down_black_hole:
$AnimationPlayer.play("Animation_Black_Hole")
animation_played = true
elif !scale_down_black_hole:
$AnimationPlayer.stop(false)
if animation_finished:
queue_free()
# print($Mesh_Black_Hole.scale)
# print(animation_finished)
pass
func _on_AnimationPlayer_animation_finished(Animation_Black_Hole):
animation_finished = true
print("End_Animation_Black_hole")
pass # Replace with function body.
func _on_OmniLight_signal_black_hole(black_hole):
if black_hole:
scale_down_black_hole = true
print("scale_down_black_hole_True)
if !black_hole:
scale_down_black_hole = false
print("scale_down_black_hole_False")
# if !black_hole:
# scale_down_black_hole = false
pass # Replace with function body.
(with var group_holes (etc.) i am experimanting right now ... so is n that sreennshot...)
Upvotes: 0
Views: 150
Reputation: 40315
I take that the code is the script attached to the "Black_Hole" Area
, despite the script being set as Spatial
. That is something you would want to set correctly.
Being the script attached to the "Black_Hole" Area
, it makes sense that it uses $AnimationPlayer
, since the "Black_Hole" Area
has an AnimationPlayer
child not surprisingly called "AnimationPlayer".
On node references
I want to comment this line:
onready var group_holes = get_node("Group_Holes")
That the "Black_Hole" Area
does not have a child called "Group_Holes". The line as is would work if the script was attached to the "Terrain" Node
.
I do not recommend to reach for a Node
that is not a child of where your script is attached. If you need to do it regardless, you need a node path that goes up (".."
), see NodePath
. and Understanding node paths.
The reason why I don't recommend it is because it is fragile (i.e. if you move the nodes around in the scene, the code is likely to break because it would be pointing to something that you moved and thus no longer there). See Node Communication.
You might also be interested in node groups.
On this line:
var group_black_holes = group_holes.get_child()
I suppose you mean to use get_children()
. I suppose this is not being highlighted as an error because you are not using types. Consider using types.
Node connections
Alright, the main act. You play the animation from this line:
$AnimationPlayer.play("Animation_Black_Hole")
Which the execution flow would only reach if scale_down_black_hole
is true
:
if scale_down_black_hole:
$AnimationPlayer.play("Animation_Black_Hole")
And you only set scale_down_black_hole
to true
here:
func _on_OmniLight_signal_black_hole(black_hole):
if black_hole:
scale_down_black_hole = true
In Godot value is considered false
if it is zeroed (e.g. null). So the execution flow only enters the conditional when black_hole
is not zeroed.
Since there is one black hole that works, I believe black_hole
is not zeroed.
However, since that one black hole that works, works regardless of with which you interact, it suggest that only black hole is getting all the signals.
If I understand correctly, you are going through some hoops to make that work. That is, instead of have the Area
connect the signals to itself, you have them connected to an OmniLight
, which then emits a signal that is supposed to be connected back to the Area
.
Thus, presumably (I don't have the code on the OmniLight
script to confirm), the black_hole
argument is the Area
that originally emitted the signal.
This is how I imagine the code in the OmniLight
script looks light:
func _on_Black_Hole_body_entered(body):
# some other code
emit_signal("signal_black_hole", black_hole)
func _on_Black_Hole2_body_entered(body):
# some other code
emit_signal("signal_black_hole", black_hole2)
func _on_Black_Hole3_body_entered(body):
# some other code
emit_signal("signal_black_hole", black_hole3)
Which is not great. Using a Signal bus we can change it, I'll get back to this.
A fix for this, without changing the approach, would be to make sure all the black hole Area
s are connected to the OmniLight
, and that the OmniLight
signal is connected to all of them as well. And passing what they should.
And to make sure only the black hole you want fires, you should check it is the intended target:
func _on_OmniLight_signal_black_hole(black_hole):
if black_hole == self:
scale_down_black_hole = true
Change of approach
Alright, I would suggest to change the approach. Having to connect every black hole is error prone. When you want to add more black holes to your scene you might forget to connected them or connect them incorrectly, as I believe you did. Thus, let us remove the need to make those connection.
I'll talk about the connection from the OmniLight
to the Area
s first. It is important, although the code will change once we introduce the signal bus…
If the OmniLight
has a reference to the black hole (which I believe it does), it can call a method on it. For example:
func _on_Black_Hole_body_entered(body):
# some other code
if body.has_method("_on_OmniLight_signal_black_hole"):
black_hole._on_OmniLight_signal_black_hole(black_hole)
# and so on for the other black holes
And thus, you don't need to have a signal in the OmniLight
that the Area
s connect to. With that we get rid of half the connections you have to make. Although the code here is not great yet.
I'll also mention that you don't need to pass the black hole itself. And - of course - you could pick a better name for the method.
But why do you do this anyway? You can connect the back hole Area
s "body_entered"
signal to themselves. And in doing so, allowing them to work without the OmniLight
. I understand you might need to notify the OmniLight
anyway, so let us address that next.
If you need the connection from the Area
to the OmniLight
, I'm going to suggest a Signal Bus (event bus). So you would have an autoload where you define the signal, then all the black_hole Area
s emit it, and the OmniLight
or whatever connects to it, without they knowing each other.
Assuming you have created an autoload SignalBus
with a trigger_black_hole
signal like this:
signal trigger_black_hole(black_hole)
The black hole Area
s can connect their own "body_entered"
signal to themselves in the black hole scene, and there emit the signal in the SignalBus
:
func _on_Black_Hole_body_entered(body):
SignalBus.emit_signal("trigger_black_hole", self)
Consider starting the animation there too.
And the OmniLight
can connect to it from code:
func _ready() -> void:
SignalBus.connect("trigger_black_hole", self, "_trigger_black_hole")
func _trigger_black_hole(black_hole) -> void:
# whatever
If the OmniLight
needs to call a method on the black hole (for example to have it start the animation), it can do so there too.
You could also pass the body if necessary, by adding a parameter in the definition of the signal, passing it as argument when you emit it, and - of course - adding it to the method that receives the signal.
Using the signal bus, you don't need to connect the signals, so you don't have to remember to connect the signals, and you won't connect the signal wrong either.
I'd advice to have everything that the black holes need to work contained in their scene. In other words, I would advice against them depending on the OmniLight
to work correctly.
Addendum
Assuming you are sending a signal like this:
func _on_Black_Hole_body_entered(body):
SignalBus.emit_signal("trigger_black_hole", self)
Where you pass self
as argument. And you receive the signal like this:
func _ready() -> void:
SignalBus.connect("trigger_black_hole", self, "_trigger_black_hole")
func _trigger_black_hole(black_hole) -> void:
# whatever
The argument black_hole
is the object that sent the signal (i.e. the black hole Area
). So you can call methods on it, for example, you have a something
method that takes a value:
func _on_Black_Hole_body_entered(body):
SignalBus.emit_signal("trigger_black_hole", self)
func something(value):
# whatever
Then you can call it like this:
func _ready() -> void:
SignalBus.connect("trigger_black_hole", self, "_trigger_black_hole")
func _trigger_black_hole(black_hole) -> void:
black_hole.something(value)
Another thing you can do is connect another signal, but on the opposite direction. I'll define a reply
signal on the Signal Bus:
signal trigger_black_hole(black_hole)
signal reply(black_hole, value)
So we can connect it on the Area
:
func _ready() -> void:
SignalBus.connect("reply", self, "_on_reply")
func _on_reply(black_hole, value) -> void:
if black_hole != self:
return
# whatever
func _on_Black_Hole_body_entered(body):
SignalBus.emit_signal("trigger_black_hole", self)
And then on the other side you do something like this:
func _ready() -> void:
SignalBus.connect("trigger_black_hole", self, "_trigger_black_hole")
func _trigger_black_hole(black_hole) -> void:
SignalBus.emit_signal("reply", black_hole, value)
Since signals don't return, you might prefer to not use them. So, yet another alternative is to go back to the idea of node groups.
You can add anode to a group from the editor, but I'll do it here from code.
For example, let us add the OmniLight
to a group I'll call "black_hole_monitors"
.
func _ready() -> void:
add_to_group("black_hole_monitors")
Here "black_hole_monitors"
is the name of the group. Which, of course, is just name. It could be whatever you prefer, as long as you know what name you are using… Because we are going to use it for communication. For example the black hole Area
s could call a method on the OmniLight
like this:
func _on_Black_Hole_body_entered(body):
for node in get_tree().get_nodes_in_group("black_hole_monitors"):
# if not node.has_method("black_hole_triggered"): continue
prints(node.black_hole_triggered())
While the OmniLight
could do this:
func _ready() -> void:
add_to_group("black_hole_monitors")
func black_hole_triggered() -> bool:
# whatever
return true
So the black hole Area
would be calling the method black_hole_triggered
on the OmniLight
and also get a return value. And of course, you could add parameters to the method, or have multiple methods you call. You might also add the black hole Area
s to their own group and access them in a similar fashion, and so on.
Note that there could be none, one, or multiple nodes on the group. So I would encourage to write the logic in such way that it works regardless of how many nodes are in the group.
Upvotes: 0