Creating scoring system in Godot : Why can't I access my score node as a Unique name? Also why did my set and get methods go wrong?

I’m trying to make a cookie catching game using Godot 4.3.

After being stuck for nearly 2 days trying to develop a working score system for each cookie the player picks up , I managed to get it to work with “$…/score” instead of " %score".

I want to know why I can’t access score node as a unique name. Brackets tutorial on Godot 4.3 said that anything with $/… is unstable so we should use unique names instead with a % sign.

The script to “score” looked like this:

extends Node

var score = 0

func add_point():
       score += 1
       print(score)
      

Then I decided to Access “score” as a unique name and attach it to each cookie script. There are 5 different looking cookies each with its own script containing the same code.

extends Area2D

@onready var score = %score

func _physics_process(delta: float)
      position.y += 100 * delta

 func _on_body_entered(body: Node2D) -> void:
	if body.name == "pink_cookie_man":
		score.add_point(
		queue_free()
	else:
		queue_free() 

Each time I run it I keep on getting Node not found relative to “/root/game/@Area2D”.

The second method involved using a canvas layer called “Display” attached to a 2D node called “HUD”. “Display” has a child Label node called “Score”.

Display script called Hud.gd :

extends Node2D

var _score = 0

func set_score(value):
	_score = value

	get_node("/root/Hud/Display/Score").text = "Score: " + str(_score)

func get_score():
	return _score

var int :
       set = set_score
       get = get_score

In the cookie scripts I put:

extends "res://scenes/Hud.gd"

func _physics_process(delta: float) -> void:
	position.y += 100 * delta

func _on_body_entered(body: Node2D) -> void:
	if body.name == "pink_cookie_man":
		get_node("/root/Hud").score+=1
		queue_free()
	else:
		queue_free()


I get "Invalid access to property key(score) on a base object of null instance.

Sorry for the wordy post. I'm a beginner and I want to know why both methods failed.

Because unique scene/name has the same-scene limitation (see more: Scene Unique Nodes — Godot Engine (stable) documentation in English)

Keep in mind that use $ or % has their utilities and you need to understand which situation one is better than the other, especially because % has limitations.

Also, if you want a really robust referencing system i recommend you use groups instead, an example to you update the score:

In Hud.gd:

extends Node2D

# Just a minor info, adding a _ before a variable/function generally means
# this variable/function is private (intended to internal use only) so
# as good pratice this should get rid of this _ or use functions to access
var _score = 0

# Store the reference for the label, so you dont need to get again every time
@onready var score_label = get_node("/root/Hud/Display/Score")

# With that you can access the hud node from anywhere, even if you
# change the scene order
func _ready():
	add_to_group("hud")

func set_score(value):
	_score = value
	score_label.text = "Score: " + str(_score)

func get_score():
	return _score

# I strong recommend to you change this variable name, using reserved
# names for variables is a bad idea
var int : 
       set = set_score
       get = get_score

In the cookie script:

# Why you're extending from hud? That doesn't make any sense
# because you don't use nothing from hud directly (and is a bad code design),
# extend from Node2D instead
#extends "res://scenes/Hud.gd"
extends Node2D

func _physics_process(delta: float) -> void:
	position.y += 100 * delta

func _on_body_entered(body: Node2D) -> void:
	if body.name == "pink_cookie_man":
		# Get the hud node from anywhare
		get_tree().get_first_node_in_group("hud")._score += 1
	
	queue_free()
# If you will delete the node anyways you dont need this else statement, just 
# delete the node after the if check
		#queue_free()
	#else:
		#queue_free()
3 Likes

you may successfully ignore any node paths by adding meta into root scene node of type nodepath and pick scene node, then set properties that lead to exact node.
@onready var label:Label=get_node(get_meta(&'label'))
and access node using id label
this approach will make editor to update nodepath automatically when you moving node’s parents in scene.
No dependency on unique name

Is there documentation on node metadata and its use? I wasn’t aware of it and now I’ve seen it twice in two days. I quick search in the documentation doesn’t seem to bring up anything addressing it.

1 Like

meta is Object related thing, not just high level Node. Meta could keep any data at runtime, but a bit limited when used from editor.


1 Like