Stop Updating Score Once Player Is Dead

Godot Version

Godot 4.2.1

Question

So I have the game running as intending, however I noticed that the score system I set up continues to count missiles and add to the score. I want it so that once the player is destroyed, any remaining missiles that were shot from the RayCast2D turret do not count towards missiles destroyed/missed counter(score).

Not exactly sure where to code this in my current turret_spawner.gd file:

extends Node2D

@export var game_stats: GameStats
@onready var rng = RandomNumberGenerator.new()
@export var turret_scene : PackedScene
@onready var timer = $Timer
@onready var player_char = $Player
@onready var score_label = $ScoreLabel

func _ready():
	update_score_label(game_stats.score)
	game_stats.score_changed.connect(update_score_label)
	
	#temp below for gameover testing
	player_char.tree_exiting.connect(func():
		await get_tree().create_timer(2.0).timeout
		get_tree().change_scene_to_file("res://scenes/gameover.tscn")
	)
	#temp above for gameover testing

func update_score_label(new_score:int) -> void:
	score_label.text = str(new_score)
	
func _on_timer_timeout():
	_TurretSpawner()

func _TurretSpawner():
	rng.randomize()
	if rng.randf_range(0.0, 30.0) < 1.0:
		var turret_spawn_pt = $Path2D/PathFollow2D
		turret_spawn_pt.progress_ratio = randf()
		
		var turret = turret_scene.instantiate()
		add_child(turret)
		turret.position = turret_spawn_pt.position

func _on_player_hit():
	timer.stop()

1 Like

If you give the player script a bool to check if the player is dead, should solve it.
Like:

func update_score_label(new_score:int) -> void:
    if(player_char.is_alive == true):
	    score_label.text = str(new_score)

In the player node you need to create the bool.
And when player dies, switch it to false

1 Like

When I implement the above code as well as a is_alive in the player script:

var is_alive: bool = true

as well as this in the turret spawner:

func update_score_label(new_score:int) -> void:
	if(player_char.is_alive == true):
		score_label.text = str(new_score)
	if(player_char.is_alive == false):
		score_label.text != str(new_score)

However, once my player character gets hit, the game errors and i get a:
invalid get index ‘is_alive’ (on base: previously freed) as well as:
W 0:00:05:0823 Standalone expression (the line has no effect).
STANDALONE_EXPRESSION
turret_spawner.gd:25

1 Like

Do you delete the player ?
So do you do
queue_free on the player ?

1 Like

In my player script I have:

signal hit
func _area_entered(_area):
		hit.emit()
		queue_free()
1 Like

You need to set bool to false, before you delete the object. You cant access a node, thats already deleted.

No wait haha .that makes No sense. Just dont delete the player. You restart the scene anyway. Dont delete the player.

If you still want to delete it, use an autoload as alternative. Like:

Global.player_exists = true

1 Like

I figured it out. Rewatched the tutorial video I was basing the score code on and I realized that I could instead reuse the score_changed signal in my _on_player_hit func to disconnect from updating the score.

Like so:

func _on_player_hit():
	timer.stop()
	game_stats.score_changed.disconnect(update_score_label)

Thank you however for helping me solve this issue :grinning:

2 Likes

This is a comparison that result in a boolean, true/false causing the error/warning since it is not in an conditinal statement as if or such.

I’d guess you only want to update if player_char.is_alive - and do nothing otherwise so you can/should remove the last if-condition.

func update_score_label(new_score:int) -> void:
    # update score if alive
	if(player_char.is_alive == true):
		score_label.text = str(new_score)
	# else do nothing
1 Like

All looks like this is not a resolved issue.
While game_stats.score_changed.disconnect(update_score_label) worked, it was a temporary solution.

As I progressed further into the development and added the game score and high score to the game over screen, it continued to count all missiles that exploded even after the player died.

So for example, with the previous code implementation, I get to a score of 5 (score is how many missiles I dodged) but the missile that killed the player and the remaining 3 missiles that spawned before the player died continue on and hit the ground and explode, thus counting towards the score. At the game over, instead of a score of 5, I get a score of 9.

Missile code:

extends Node2D
@onready var audio = $AudioStreamPlayer2D
@onready var score_component = $ScoreComponent as ScoreComponent
@onready var explosion_sprite = $AnimatedSprite2D

func _ready() -> void:
	explosion_sprite.animation_finished.connect(func():
		score_component.adjust_score()
	)

Score Component code:

class_name ScoreComponent
extends Node
#Export game stats to manipulate game score
@export var game_stats: GameStats
#Export amount score changes by
@export var adjust_amount = 1

#func used to activate this component.
#By default it wil use the adjust_amount when called but
#we can optionally pass in a different amount
func adjust_score(amount: int = adjust_amount):
	game_stats.score += amount

Game Stats code:

class_name GameStats
extends Resource

#everytime the score is set, it will emit a score signal
@export var score: int = 0:
	set(value):
		score = value
		score_changed.emit(score)

@export var highscore: int = 0

#this signal will emit a new score
#we want to emit this signal everytime the score changes
signal score_changed(new_score)

I’m kinda stuck on where to go in order to have it so that if the player is dead, stop adding to the score.

1 Like

You could make a boolean that stores whether the player is dead or not and check that when you try to add to the score.

1 Like

Since the missile explosion is the node that adds to the score, would that imply to add a player node in the missile explosion?
var is_alive := true

1 Like

No, I don’t see why you would add an additional player when you explode a missile. If you meant that you would change the value when the missile explodes, you only change it when the player dies.

1 Like

I guess what I mean is that the main world/level scene has a packed scene called turret (a RayCast2D), which in itself, has another packed scene called missile. And when that missile collides with either the tilemap or the player, it then changes scene to become the missile explosion scene. Then on top of all this, the turret packed scene is spawned along on a Path2D/PathFollow2D

Theres kinda no way to reference the player itself on any of these packed scenes, at least that I am aware of.

I’ve tried messing around with creating another func in the score component, and then using if/elif statements within the missile explosion code. And even the game stats code itself. But all debugging sessions still end with either the game crashing due to some error, or the score still counting any missiles exploding after the player is dead.

1 Like

All, I’ve finally solved this with the use of a Global variable.

missile_explosion code:

func _ready() -> void:
    if not Global.instance_player == 0:
        explosion_sprite.animation_finished.connect(func():
            score_component.adjust_score()
        )

player code:

func _area_entered(_area):
    hit.emit()
    print("Hit")
    queue_free()
    Global.instance_player -= 1

Just in case anyone from the future has the same or similar problem.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.