Creating easily accessible groups of resources

Godot Version



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():
    return enemy_dict[id]

func init_dict():
    for e in enemies:
        enemy_dict[] = 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 Enemys manually put into its array. This allows me to preload the EnemyMap and access my Enemys 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.


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.

1 Like

I think using the file path for your resources’ folder is a good way to go about it.

The StringNames you’ve defined are also easily maintainable as a sudden change in naming convention only needs correction in this one file. I think your system looks pretty good.

One thing I would recommend is to print an error in your console if the path is no longer valid (e.g. if the directory changes). An error will happen regardless but some extra details on how such an incident is swiftly fixed will save your future self from some debugging.