How do I count score from procedurally generated enemies?

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

In my Main scene, I have the following script attached to a timer:

func _on_EnemySpawnTimer_timeout():
    var enemyOptions = [batEnemy.instance()]
    var enemyInstance = enemyOptions[randi() % enemyOptions.size()]
    enemyInstance.set_name("batOne")
    enemyInstance.position = Vector2($SpawnLocationAir.get_global_position().x, $SpawnLocationAir.get_global_position().y)
    add_child(enemyInstance)
    print("Made an enemy")

I also have a RichTextLabel, a child of Main. I have collisions between player and enemies working, but the score is not counting up. I attempted making a Singleton, but for some reason the text would not update.

This is the code within my RichTextLabel node:

export(int) var score = 0
func _physics_process(delta):
    print(score)
    self.set_text(str(score))

And within the bat scene:

var score = ScoreCounter.score

func _process(delta):
	position.x += -LEFTIMPULSE


func _on_Hitbox_body_entered(body):
	print("Killed Bat")
	ScoreCounter.score += 1
	queue_free()


func _on_Hitbox_area_entered(area):
	print("Killed Bat")
	ScoreCounter.score += 1
	queue_free()

I’m quite stumped, as I’m not sure what is happening. When printing the score, I get a large amount of 0’s, even though the variable should be changing… Any amount of help would be extremely kind. Thank you.

Is ScoreCounter a singleton?

exuin | 2021-04-14 21:23

Yes, it is a Singleton being instanced in Main.

frannydancis | 2021-04-14 21:40

Huh? Singletons aren’t instanced by the user in code, they’re instanced by the engine and added to the root node before the main scene is added.

exuin | 2021-04-14 21:59

I’m instancing scoreCounter.tscn within Main, scoreCounter.tscn is also the singleton. Am I missing/not getting something?
enter image description here

enter image description here

frannydancis | 2021-04-14 22:02

So it’s in the scene tree twice? Check the scene tree using the remote tab when you run it.

exuin | 2021-04-14 22:09

You’re right, it is in the scene tree twice. Once above Main, and once as a child of Main. Certainly a problem. How do I get it to display on the screen if I remove it from being a child of Main?

frannydancis | 2021-04-14 22:15

Well, you can either use CanvasLayers or you can make it not a singleton and use signals to change the score.

exuin | 2021-04-14 22:20

I tried using signals, but was having difficulty sending a signal from a procedurally generated node, which in this case is the bat enemy. Do you have any resources on that? How would you go about using CanvasLayers for a Singleton?

frannydancis | 2021-04-14 22:33

You can connect signals through code by using the connect function. When the enemy dies, you can emit a signal to the score counter.

As for a CanvasLayer, just make the CanvasLayer the Singleton and the text a child of it.

exuin | 2021-04-14 22:35

:bust_in_silhouette: Reply From: Wakatta

Read through the comments and saw the quickest way to resolve your issue is to remove score counter from your main scene.

Since you have ScoreCounter as a Singleton you can access its variables and functions by calling something like ScoreCounter.score

Some of your code concerns me though and some clarity is needed on your intended results

position.x += -LEFTIMPULSE #???

and

var enemyOptions = [batEnemy.instance()] #creates and array with 1 content
var enemyInstance = enemyOptions[randi() % enemyOptions.size()] #size will always be 1

also

var score = ScoreCounter.score

changing score here in your BatScene.gd would only update that score variable and not the ScoreCounter.score’s so its redundant since you’re already setting the singleton var properly using ScoreCounter.score += 1

Side note

Rather than using func _physics_process(delta): which should only really be used for physic interactions use do something like

func _on_Hitbox_body_entered(body):
    print("Killed Bat")
    ScoreCounter.score += 1
    ScoreCounter.set_text(str(ScoreCounter.score))
    queue_free()

position.x += -LEFTIMPULSE #???

My game has the illusion of the player running to the right, when in reality everything is moving towards the left.

var enemyOptions = [batEnemy.instance()] #creates and array with 1 content
var enemyInstance = enemyOptions[randi() % enemyOptions.size()] #size will always be 1

Currently, this is a placeholder as I go about creating more enemies.

hanging score here in your BatScene.gd would only update that score variable and not the ScoreCounter.score’s so its redundant since you’re already setting the singleton var properly using ScoreCounter.score += 1

Very true! I went ahead and fixed that as well. Thanks for catching that. Now that it is updating properly, how do I go about getting it to display on the screen?

frannydancis | 2021-04-14 23:17

edited my answer to reflect that

Wakatta | 2021-04-14 23:19

That code is getting the text to update properly, but it is not appearing once I launch the game.

frannydancis | 2021-04-14 23:23

The RichTextLabel?. Make sure to position it where needed and ensure its set to visible in its own scene

Wakatta | 2021-04-14 23:35

Ah I’ve noticed the problem. My background is appearing on top of the label, so I cannot see it. Thank you for your help!

frannydancis | 2021-04-14 23:44