Ref-Counted object usage

Godot Version

4.7.2

Question

Is it ok to have a bunch of string names or any variable type for that matter put in a ref-counted class to be used across the project?

for example:

class_name StateNames extends RefCounted

@warning_ignore("unused_private_class_variable")
const _PLACE_HOLDER :StringName = &""


#region /// Sub-Hierarchical state machine names
const GROUND_ACTIONS :StringName = &"GROUND_ACTIONS"
const AIR_ACTIONS :StringName = &"AIR_ACTIONS"
const GROUND_COMBO :StringName = &"GROUND_COMBO"
const AIR_COMBO :StringName = &"AIR_COMBO"
#endregion


#region /// Leaf state names
#Movement
const FLOOR :StringName = &"FLOOR"
const FOLLOW :StringName = &"FOLLOW"
const JUMP :StringName = &"JUMP"
const FALL :StringName = &"FALL"
const CROUCH :StringName = &"CROUCH"
const SLIDE :StringName = &"SLIDE"

#Attack
const ATTACK_01 :StringName = &"ATTACK_01"
const ATTACK_02 :StringName = &"ATTACK_02"
const ATTACK_03 :StringName = &"ATTACK_03"
const AIR_ATTACK_01 :StringName = &"AIR_ATTACK_01"
const AIR_ATTACK_02 :StringName = &"AIR_ATTACK_02"

#health
const DEATH: StringName = &"DEATH"
const HURT: StringName = &"HURT"

#menu states
const SETTINGS: StringName = &"SETTINGS"
const MAIN_MENU_FRONT: StringName = &"MAIN_MENU (FRONT)"
#endregion
class_name PlayerHSM extends BaseStateMachine


func transitions() -> void:
	initial_state = states[StateNames.GROUND_ACTIONS]

	add_transition(ANYSTATE, states[StateNames.HURT], &"HIT")
	add_transition(ANYSTATE, states[StateNames.DEATH], &"DEATH")
	
	add_transition(states[StateNames.HURT], states[StateNames.GROUND_ACTIONS], &"GROUNDED")
	
	add_transition(states[StateNames.GROUND_ACTIONS], states[StateNames.AIR_ACTIONS], &"AIRBORNE")
	add_transition(states[StateNames.AIR_ACTIONS], states[StateNames.GROUND_ACTIONS], &"GROUNDED")

If you want to access the variables across the project, it maybe better to add the script(s) to Autoload.

Yes, perfectly fine. You can also put variables in there if you need. If you declare them static, you’ll be able to access them globally the via class name without needing to instantiate any objects.

This pretty much gets you the same global storage functionality as using an autoload, but you don’t need to drag a dangling node along.

I actually prefer using this approach over autoloads for global data storage.

I thought it was possible to make Autoloads for Nodes and RefCounted scripts last time I used it. I don’t think Autoloads need to always create dangling nodes.

Nice thing about Autoloads is everyone knows there in order to look there in order to find the things that are intentionally global. But both class_name and Autoloads might be seen as cluttering the global name space.

I like to avoid globals of both kinds as much as possible. If not possible I prefer Autoloads for global variables or helper functions. I try to reserve class_name for everything that is part of the program’s main domain. For anything else scripts can be locally loaded by file name in order to make them accessible from other scripts with load() (or preload).

Autoloads are always nodes parented to scene tree’s root. That’s the mechanism. You can’t setup a non-node class as an autoload because its instance cannot be added to the scene tree. The engine will complain and disobey.

In both cases, whether using an autoload or a static class, you’ll expend exactly one name in the global namespace. So in that respect it makes no difference.

Minimizing the usage of global variables is always good, of course.

Since I remembered Godot not complaining last time I added a script as a global I now tried it out.
In fact I can add a script as a global, but when I run it I get an error. Maybe something to be aware of.

Here the added script:

Here the error when running it:

I assumed it would be fine to add scripts since it is not prohibited in the Autoload manager. Good to know that Godot actually expects Nodes.

The engine will in fact print some errors in the output immediately after you set up an autoload in the project settings.

Btw, you can see all your autoloaded nodes at runtime if you look at the remote scene tree. So autoloads by design always need to be present in the tree, and that wouldn’t be possible if the class is not a node class.