Reputation: 31
I am making a 3d endless runner game. but the problem lies in collecting the coin.
I want to display the coins that are collected by the player.
This is my label script:
This is my Globalscript:
This is my Coin script:
I was expecting that if i collected a coin. my coin display would display how many coins I have collected.
so far, my collision shapes and the coin detect each other as it shows "collected" on my output :
but in game, it does not display that I collected it:
Upvotes: 0
Views: 523
Reputation: 40295
For what I gather there are two "body_entered" signals:
Global_Coin
(I'm taking it is an autoload) has a _on_body_entered
signal defined, which passes no arguments:
extends Node
signal _on_body_entered
Then in your Area3D
you connect it to the _on_body_entered
method.
And it would be emitted by the Label
of all things, from the _on_body_entered
method which I believe is not called at all.
The Area3D
has a body_entered
that has a body:Node3D
parameter.
This signal would be emitted by the Area3D
when some body enters it.
And I'm guessing is connected to the _on_body_entered
method by other means, which explains how the "collected"
message shows up in output.
Note: I'm confident that the body_entered
signal of the Area3D
is not connected to the _on_body_entered
of the Label
because that method has no parameters, and thus you would have an error if it were connected, given that the body_entered
signal from Area3D
passes an argument.
Thus:
Pick different names for different things. Otherwise you will end up confusing whoever reads your code, which most of the time is yourself (which I believe is the case here).
Single responsibility principle: The job of the Label
is to display text. Why is the Label
responsible from emitting a signal (and of "body entered" of all things)? It should not be emitting a signal for this (that is not its responsibility). In fact, it makes more sense that it would be receiving it.
The following is what makes sense:
Make sure the body_entered
signal of the Area3D
is connected to the _on_body_entered
method in the scrip attached to the same Area3D
. I believe this is already the case, but I do not see the usual green icon that indicates the connection, thus I suggest to double check.
Have the _on_body_entered
method in the Area3D
emit the _on_body_entered
signal from Global_Coin
. In fact, I'd suggest to change the name of the signal to something more meaningful, e.g. coin_collected
.
Connect from code the _on_body_entered
signal from Global_Coin
to the _on_body_entered
method in the Label
(currently you do this in the Area3D
), so the Label
can increment its count.
In general the flow of data would be like this:
Area3D
Area3D
emits its Area3D.body_entered
signal.Area3D
handles the Area3D.body_entered
signal, and emits the Global_Coin._on_body_entered
signal, and also queues itself from removal.Global_Coin._on_body_entered
signal and increments its count. I'll insist in renaming the singal.Furthermore, we can put a setter on coins
instead of calling _ready
.
Thus:
Global_Coin:
extends Node
signal coin_collected
Area3D:
extends Area3D
func _on_body_entered(body:Node3D) -> void:
prints("collected")
Global_Coin.coin_collected.emit()
queue_free()
Label:
extends Label
var coins:int = 0:
set (mod_value):
coins = mod_value
text = str(coins)
func _ready() -> void:
Global_Coin.coin_collected.connected(_on_coin_collected)
# coins = 0
func _on_coin_collected() -> void:
coins = coins + 1
Upvotes: 0
Reputation: 70307
To update a label, you need to update it's text
field. It won't automatically detect changes to variables it was originally constructed with.
func on_body_entered() -> void:
coins += 1
text = str(coins)
...
You can automate this with a setter on the field.
var coins = 0:
set(value):
coins = value
text = str(coins)
func on_body_entered() -> void:
self.coins += 1
...
We need self.coins
so as to trigger our own setter. Setting the variable directly bypasses it. But this has the advantage that, whenever anybody anywhere sets the coins
variable, the label will update alongside it.
The above syntax is for Godot 4. If you're still on Godot 3, it looks like this.
var coins = 0 setget _set_coins
func _set_coins(value):
coins = value
text = str(coins)
func on_body_entered() -> void:
self.coins += 1
...
Upvotes: 0