Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information