Skip to content

Storable Objects

kobewi edited this page Feb 24, 2024 · 2 revisions

Storable objects are anything that you'd want its state to be stored (saved), e.g. switches, breakable walls, collectibles. The idea is that every object has an ID that identifies it. Mark an object as storable when it's being initialized (_ready()), providing a callback for when the object is already stored (usually queue_free()). If the object was already stored, the callback will be immediately called. If it's not, you call the store method at a specific event (the player pulls a lever, collects an item etc.). Objects can be either stored or not, and stored state can't be reverted (using the public API at least). If you need more object states or toggleable states, you can take advantage of MetSys' object IDs. Example storable object implementation:

# Chest.gd
func _ready():
	if MetSys.register_storable_object(self): # Calls queue_free() if already opened.
		return

	unrelated_call()

func open():
	MetSys.store_object(self)
	$AnimationPlayer.play("Open")
	await $AnimationPlayer.animation_finished
	queue_free()

The above example shows a Chest object. It's initialized at the beginning. When player opens a chest, it's marked as "stored" and plays the opening animation and then disappears. When the player enters the room again, the chest will disappear at start, because it was stored and the callback will be called. Few things to note:

  • register_storable_object() takes a callback, but defaults to queue_free() for Nodes and free() for non-RefCounted Objects.
  • The callback is called only when registering. Storing an object just toggles a flag, it doesn't do anything in itself.
  • register_storable_object() returns true when the object was already stored, so you can use it to stop further initialization logic.

Alternate method for registering objects is register_storable_object_with_marker(). It takes object, callback and marker index. When used, the object will be be marked on map when it first appears and marked again when stored. You can define default markers in map theme or you can also provide a custom symbol index to the method to customize how the element is marked on the map. If marker index is -1, that marker will not appear. You can make marker appear only when the object is discovered or only when it's stored or both.

Object IDs and coordinates

Separately from the storable objects there exists an object ID system. It's used by storable object methods to determine whether the object was stored or not, but it can be used manually. The ID is a String and is determined ad hoc from the object instance. If the object is a Node, the ID will be created from scene name, parent node and node name. E.g. if you have this scene structure:

Map (Forest.tscn)
- Objects
  - Chest

The Chest will have ID Forest/Objects/Chest. This system ensures that any node in your world can be identified by unique ID (conflicts are possible, but typical usage won't cause them), thus allowing for automatic saving of object's state. You can get ID of any object by using MetSys.get_object_id(object)

If your object is not a node, or for some reason you want them to share ID, you can manually assign ID by setting object_id metadata, e.g. object.set_meta(&"object_id", "my_id"). Another alternative is implementing _get_object_id() method in the object (the returned ID will be cached in meta). The meta and method will have priority over the auto-ID. If the ID can't be determined, get_object_id() will return empty String.

Another related method is get_object_coords(). It works just like get_object_id() (including object_coords meta and _get_object_coords() method), but instead it returns object's coordinates on the world map. You can use it to draw custom ad hoc stuff on the minimap or manually assign object markers. If the provided object is a Node2D, it will return an accurate coordinates. If it's a plain Node, it will return coordinates of the top-left corner of the current room (note that it needs to be inside a scene assigned to some map room). If the coords can't be determined, Vector3i.MAX is returned.