Reputation: 3
I am following along with the "Your first 3D game" tutorial on Godot Docs. I am making slight alterations to make my own game (a Crash Bandicoot remake). I'm currently on the "Score and replay" chapter.
The main difference is that my obstacles are already in the scene, whereas the tutorial has obstacles that are randomly generated.
Here is the script attached to my level scene:
extends Node
export (PackedScene) var obstacle_scene
func _start():
var obstacle = obstacle_scene.instance()
obstacle.connect("squashed", $UserInterface/ScoreLabel, "_on_Obstacle_squashed")
Note that in the editor my obstacle_scene is hooked up to my Obstacle.tscn.
And here is the code attached to UserInterface/ScoreLabel:
extends Label
var score = 0
func _on_Obstacle_squashed():
score += 1
text = "Score: %s" % score
Expected result: I want to increase the score every time I jump on a cube that is already in the scene. Unlike the tutorial, I am not randomly generating obstacles (or "mobs" as they're called in the tutorial).
Actual result: I can successfully run the game without errors, but jumping on obstacles does not change the score.
I hope I gave enough information but happy to share more code if necessary.
Upvotes: 0
Views: 136
Reputation: 40315
I believe the function _start
is not running at all, since you didn't share any code that calls it, I can't find it in the linked tutorial… And you probably wanted to use _ready
.
There is another issue: the code in _start
instantiates the scene (creates a new instance), and connects it. But this new instance is never added to the scene.
To be clear, there can be multiple instances of a scene. For example, some could be added in the editor, and others created from code. And each one of those instances can emit signals. And you need to have those signals connected if you want to use them.
If you have added instances from the editor, you can connect their signals from the editor too. Go to the Node panel on the Signals tab, double click the signal you want and Godot will bring a window where you can specify where to connect the signal to.
It is also possible to connect from code the signals of instances created on the editor… However, I reiterate, that is not what you are doing. You are creating a new instance by calling the instance
method. This new instance is distinct from any instance added from the editor. Instead you would get the instances form the scene tree, for example with get_node
or the $
syntax.
For example:
func _ready() -> void:
$obstacle.connect("squashed", $UserInterface/ScoreLabel, "_on_Obstacle_squashed")
And you would have to do that for each instance:
func _ready() -> void:
$obstacle.connect("squashed", $UserInterface/ScoreLabel, "_on_Obstacle_squashed")
$obstacle2.connect("squashed", $UserInterface/ScoreLabel, "_on_Obstacle_squashed")
$obstacle3.connect("squashed", $UserInterface/ScoreLabel, "_on_Obstacle_squashed")
# …
On the other hand, if you created the instances from code, then you can't connect them from the editor and your only option is to connect them code. As the tutorial does. So, we can take an example form the tutorial:
var mob = mob_scene.instance()
# …
add_child(mob)
mob.connect("squashed", $UserInterface/ScoreLabel, "_on_Mob_squashed")
As you can see, it creates a new instance with the instance
method. Then adds it to the scene tree as a child of the Node where this script is running by using the add_child
method. And finally it connect the signal.
Anyway, I would like to push you into another direction: You can create a signal bus (event bus). Which is a common pattern in Godot projects.
The insight is that an object can make another object emit their signals.
What you do is create a new script, extending Node, and just with the signals you want. For example:
extends Node
signal squashed
And not make it an autoload. To do that you to project settings on the AutoLoad tab, then select your script and give it a name. I'll call it SignalBus
.
Now, in your code you can emit that signal, for example:
func squash():
SignalBus.emit_signal("squashed")
queue_free()
And you can connect and handle that signal:
func _ready() -> void:
SignalBus.connect("squashed", self, "_on_squashed")
func _on_squashed() -> void:
prints("Something")
Or, in your case:
func _ready() -> void:
SignalBus.connect("squashed", $UserInterface/ScoreLabel, "_on_Obstacle_squashed")
The trick here is that the cubes don't have the "squashed"
signal, the SignalBus
has it, and the cubes tell the SignalBus
to emit it. So you don't have to connect the instances of your scene (which, again, don't have the signal), but you only need to connect SignalBus
, because it is what is actually emitting signals.
Upvotes: 0
Reputation: 51
Is the squashed
signal ever being called?
If not, the _on_Obstacle_Squashed()
function will never be called.
Upvotes: 0