Godot Version
4.5 Stable
Question
I want to use a Resource to define all my characters’ stats, then save those as .tres files to be read from at runtime. Basically, like this:
class_name StatData
extends Resource
@export var max_hp: float
@export var attack: float
But I have a few issues.
- Stats in my game aren’t just simple floats, but RefCounteds with their own data like lists of modifiers, methods to recalculate, etc.
- I’m pretty sure I shouldn’t and don’t want to use the actual Resource itself at runtime when changing the stats, like by dealing damage or equipping items. I hear it’s bad practice to modify Resources at runtime, and I can see why. I want the Resource to be a simple data container that lets me set up the base stats, and maybe I can even read from it during the game to display said base stats for each character, but I don’t think I should be changing it around in-game. I feel like I should have a separate class like a RefCounted or even a Node that gets modified instead. Right?
So, I ended up doing something that feels kind of silly. I have the Resource shown above, and then I have a node called a StatManager that reads from that at runtime to set itself up, like this:
class_name StatManager
extends Node
var max_hp: Stat
var attack: Stat
func setup(stat_data: StatData):
max_hp = Stat.new(stat_data.max_hp) #sets the base value of the Stat class
attack = Stat.new(stat_data.attack)
Then I got to thinking… this feels kind of convoluted and tightly coupled. It is, right? If it is, then how should I go about creating a class that’s safe and simple to modify during runtime with the stats in it?
One idea is to use inner classes. I think this might be good, but I’m asking here. Like this:
class_name StatData
extends Resource
@export var max_hp: float
@export var attack: float
class Stats:
var max_hp: Stat
var attack: Stat
func create_stats() -> Stats:
var new_stats := Stats.new()
new_stats.max_hp = Stat.new(max_hp)
new_stats.attack = Stat.new(attack)
return new_stats
...
class_name StatManager
extends Node
var stats: StatData.Stats
func setup(stat_data: StatData):
stats = stat_data.create_stats()
This fixes the coupling issue. I’m just not sure if it’s overly complicated. Does this seem reasonable?
I think I was actually told by someone much more experienced than me that the above method would work for me, if I’m not mistaken about what they meant. I just didn’t get it yet at the time.
The reason I’m not just directly exporting from within the node is that I am keeping my data separate from some of my generic enemy scenes, so I’m purely just using .tres files to define one base scene for multiple enemies instead of making a scene for each one. This is important.
What are your thoughts?

