You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
object: add ability to tag arbitrary objects with arbitrary tags and values
Modules define lists of objects, e.g. a `SpriteRenderer` module may define
```zig
sprites: mach.Objects(struct {
// ...
}),
```
Previously, the only way for another Mach module to 'attach data to a sprite object' or 'tag a sprite' would be to (ab)use the graph relations system, creating their own object and using parent/child relations to express that the sprite has some tag/data associated with it. For example:
```zig
// Game.zig
is_monster: mach.Object(struct{}), // empty object just to indicate 'some other object is a monster'
// ...
// Create a 'tag object'
const is_monster_tag_obj_id = game.is_monster.new(.{});
// Add the 'tag object' as a child of our sprite
sprite_renderer.sprites.addChild(my_sprite_id, is_monster_tag_obj_id);
// ...
```
This usage of the API was quite ugly/usage, and importantly eliminated your ability to use the parent/child relations for _other_ things where they are more appropriate. However, it did mean that you didn't have to go and fork+modify the `SpriteRenderer` module that you e.g. imported as a reusable package.
With this change, we add object _tags_ and _tags with values_. Any module can add their own tags or tags with values to any object, whether it is from their module or not. For example, the `is_monster` example above could now be written as:
```zig
// Game.zig
pub const mach_tags = .{ .is_monster };
// ...
try sprite_renderer.sprites.setTag(sprite_id, Game, .is_monster, null);
const is_monster: bool = sprite_renderer.sprites.hasTag(sprite_id, Game, .is_monster);
// is_monster == true!
// No longer a monster
try sprite_renderer.sprites.removeTag(sprite_id, Game, .is_monster);
```
This allows for effectively tagging objects as distinct kinds, states, etc. even though they aren't our object and we can't modify their `struct {}` type to include an `is_monster: bool` field of our own.
Internally, the implementation stores tags using a hashmap under the assumption that not all objects in a list will have a tag.
Tags with values work almost identically, the only difference is that the last parameter to `setTag` is set to another `mach.ObjectID` which points to whatever arbitrary data you'd like to attach to the object, and `getTag` returns it. For example:
```zig
// Game.zig
pub const mach_tags = .{
/// Whether a sprite is a monster
.is_monster,
/// Whether a sprite has a friendly sprite attached to it
.{ .friend, Sprite, .sprites },
};
// ...
try sprite_renderer.sprites.setTag(sprite_id, Game, .friend, friendly_sprite_id);
const has_friend: bool = sprite_renderer.sprites.hasTag(sprite_id, Game, .friend);
// has_friend == true!
// Get our friend
const friend_id: mach.ObjectID = sprite_renderer.sprites.getTag(sprite_id, Game, .friend);
// friend_id == friendly_sprite_id
// Delete our friend
try sprite_renderer.sprites.removeTag(sprite_id, Game, .friend);
```
Signed-off-by: Emi Gutekanst <[email protected]>
0 commit comments