Godot Version
4.2.2
Question
This is a design pattern question. I find myself often creating many instances of a custom resource type, which I’d like to be able to access by an ID. Resources naturally have their RID and their path, but I’d like something more readable. What I find myself doing is creating a second resource type with a single instance which contains an array of all my instances of the first resource type, and allows access by an ID I define as a constant somewhere.
Simplified example:
class_name Enemy extends Resource
@export var id: StringName
@export var name: String
@export var sprite: Texture
class_name EnemyMap extends Resource
@export var enemies: Array[Enemy]
var enemy_dict = {}
func get_enemy(id: StringName) -> Enemy:
if enemy_dict.is_empty():
init_dict()
return enemy_dict[id]
func init_dict():
for e in enemies:
enemy_dict[e.id] = e
class_name EnemyIds
const GHOST = &"ghost"
const ZOMBIE = &"zombie"
const ALIEN = &"alien"
Then I would have instances of Enemy
with those ID’s, and an instance of EnemyMap
with the three Enemy
s manually put into its array. This allows me to preload the EnemyMap
and access my Enemy
s by ID.
It works, but it’s a decent amount of boilerplate. In one project, I’ve already done this four times for different resource types that I want to access easily. I’m looking for recommendations for a more streamlined or idiomatic pattern to accomplish this.
EDIT
Upon further consideration, I think we can simplify away the EnemyMap
layer if we rely on filepaths matching IDs. Then you can do something like:
class_name Enemies
const ENEMY_PATH_BASE = "res://data/enemies/%s.tres"
const GHOST = &"ghost"
const ZOMBIE = &"zombie"
const ALIEN = &"alien"
static func load_enemy(id: StringName) -> Enemy:
return load(ENEMY_BASE_PATH % id)
Then elsewhere you can say Enemies.load(Enemies.GHOST)
. I’m a little wary of relying on string replacement in filepaths like that, but it is simpler. Still welcome any advice.