In the engine, resources are used to save and load lots of data including scenes, tilemaps, materials, particle shaders, etc. They're Godot's scriptable objects that can be easily saved to and loaded from files.
Resources aren't designed specifically for savegame data but they're very powerful and flexible so you can use them for that purpose. At GDQuest, this is our preferred method when we need structured, complex save data or want to take advantage of the editor to inspect and edit save files during development.
Here's a simple example of how to use resources to save and load nested, strongly-typed save data.
First, we define the resource types themselves. They're just scripts that extend Resource, with an exported variable for each piece of data we want to strongly type and save. Our player has an inventory and we want to save each inventory item. We first create a resource for the inventory item:
class_name InventoryItem extends Resource
@export var name := "item"
@export var quantity := 1
@export var value := 0
We can create another resource to hold all the player save data, including an array of inventory items:
class_name PlayerSaveData extends Resource
@export var health := 100
@export var inventory: Array[InventoryItem] = []
Now you can save player data by creating instances of these resources. You can create the resources in the editor directly, or in code like this:
func create_save():
var sword := InventoryItem.new()
sword.name = "sword"
sword.quantity = 1
sword.value = 50
var potion := InventoryItem.new()
potion.name = "potion"
potion.quantity = 3
potion.value = 10
var player_data := PlayerSaveData.new()
player_data.health = 100
player_data.inventory = [sword, potion]
ResourceSaver.save(player_data, "user://savegame.tres")
To save any resource and all the sub-resources (like our inventory items), you just call ResourceSaver.save() with the resource and the file path.
To load the saved data back, use ResourceLoader.load() (or just GDScript's load() function):
var loaded := ResourceLoader.load("user://savegame.tres") as PlayerSaveData
The file extension can be .tres to output a text file or .res for a binary output. Either way you can load the file the same way, so you can use text during development and switch to binary for release.
I recommend it for: Complex game data and anything that benefits from type safety
Pros: Strongly typed data, editor integration, you can reference and save resources you use throughout your game codebase directly (like character stats)
Cons: It's a bit more complex when you're getting started. Resources can contain embedded scripts, which means loading untrusted resource files can execute arbitrary code.
NOTE:Use the add-on
Godot Safe Resource Loader to safely load resources from untrusted sources like user-generated content. It's a drop-in replacement for
ResourceLoader that prevents loading resources that contain scripts.