Why Custom Resources Matter: The First Step Toward Data-Driven Design
When developing games in Godot Engine, managing in-game data is an unavoidable challenge. Character stats, item definitions, enemy AI settings—much of this data determines game behavior. If you write this data directly into nodes or scenes, data reusability becomes difficult, and as project scale grows, management becomes complex and changes become challenging.
This is where Custom Resources come in. Custom Resources extend Godot's powerful Resource system to create and save custom data types. Similar to Unity's ScriptableObject, they are key to separating game logic from data and implementing Data-Driven Design.
Data-driven design is a design philosophy where game behavior is controlled by data rather than code. This allows non-programmers to adjust game balance by editing data, dramatically improving development flexibility and iteration speed.
Basic Concepts of Custom Resources
In Godot, a resource is a data container that can be saved to disk. Most non-node data in a project—scenes, scripts, textures, audio—is treated as resources. Custom Resources are defined by creating scripts that inherit from the Resource class.
1. Defining Custom Resources
Custom Resources are created as GDScript files that inherit from the Resource class. Within this script, define properties you want to save using the @export annotation.
# res://resources/character_data.gd
# Inherit from Resource class to function as a Custom Resource
class_name CharacterData extends Resource
# Properties marked with @export become editable in the Inspector and saved to resource files
@export var character_name: String = "New Character"
@export var max_health: int = 100
@export var attack_power: float = 15.0
@export var skills: Array[String] = []
# You can also define methods to access data
func get_description() -> String:
return "Name: %s, HP: %d, ATK: %.1f" % [character_name, max_health, attack_power]
2. Creating and Editing Resource Files
After saving the above script, create a new resource in the Godot editor by selecting your defined CharacterData type from "Create New Resource" and save it as a .tres (Text Resource) or .res (Binary Resource) file.
Opening the saved resource file (e.g., res://data/player_stats.tres) in the Inspector allows you to edit properties defined with @export through the GUI. This lets you adjust character stats without changing any code.
Practical Application: Building an Item Database
One of the most powerful applications of Custom Resources is building databases for in-game items and entities.
3. Defining Item Resources
First, define a Custom Resource that serves as the foundation for all items.
# res://resources/item_data.gd
class_name ItemData extends Resource
@export var item_id: int = 0
@export var item_name: String = "Unknown Item"
@export_multiline var description: String = "A mysterious item."
@export var icon_texture: Texture2D # Icon textures can also be saved as resources
@export var stackable: bool = true
@export var max_stack: int = 99
4. Creating Derived Resources
When specific item types (e.g., weapons, potions) need unique properties, create Custom Resources that inherit from ItemData.
# res://resources/weapon_data.gd
class_name WeaponData extends ItemData
@export var attack_bonus: float = 5.0
@export var weapon_type: String = "Sword"
@export var two_handed: bool = false
5. Using Resources In-Game
In-game inventory and shop systems load and use these resource files. Once loaded, resources are shared across multiple locations, making them memory-efficient.
# Script for a node managing inventory
extends Node
# Export weapon resource directly and set it from Inspector
@export var equipped_weapon: WeaponData
func _ready():
if equipped_weapon:
print("Equipped weapon: %s" % equipped_weapon.item_name)
print("Attack bonus: %s" % equipped_weapon.attack_bonus)
# Execute game logic based on data
if equipped_weapon.two_handed:
print("This is a two-handed weapon.")
# Example of loading resources from external files
func load_item_data(path: String) -> ItemData:
# Load resource file using ResourceLoader.load()
var item_resource = ResourceLoader.load(path)
if item_resource is ItemData:
return item_resource
return null
Benefits of Custom Resources and Data-Driven Design
Using Custom Resources provides significant benefits:
| Benefit | Description | Relation to Data-Driven Design |
|---|---|---|
| Data Separation | Game logic (GDScript) and data (.tres files) are completely separated, improving code readability and maintainability. | Data becomes independent from code, making changes easier. |
| Reusability | Once created, resource files can be shared and reused across multiple scenes and nodes, preventing data duplication and maintaining consistency. | Data definitions are centralized (Single Source of Truth). |
| Editor Integration | @export properties appear in Godot's Inspector, allowing designers and planners to edit data intuitively without programming knowledge. | The entire development team gains easy access to data. |
| Instantiation | Unlike nodes, resources don't belong to the scene tree. The Resource.duplicate() method easily creates data copies (instances). | Provides a foundation for dynamically generating and modifying data at runtime. |
Summary: Making Projects Scalable with Custom Resources
Godot Engine's Custom Resources are not just data storage mechanisms—they're powerful tools for evolving your project's design philosophy toward data-driven approaches.
For beginners, start by introducing Custom Resources with basic character stats or simple item definitions. This dramatically improves game data management and establishes a scalable design foundation capable of handling larger, more complex projects.
Mastering Custom Resources is an important step toward taking your Godot Engine development to the next level.