Dynamic components
A component is nothing more than a type safe entity id.
The component uses a
lazily acquired entity. It does not require the world since the entity is
spawned in the STATIC
global namespace which is shared across all worlds.
It is entirely possible to create a component at runtime for e.g; a local system.
#![allow(unused)] fn main() { registry().with(HierarchicalLayer::default()).init(); let mut world = World::new(); let position: Component<Vec2> = world.spawn_component("position", |desc| { let mut buf = ComponentBuffer::new(); <Debug as MetaData<Vec2>>::attach(desc, &mut buf); buf }); let id = Entity::builder() .set(position, vec2(1.0, 6.4)) .spawn(&mut world); tracing::info!("world: {world:#?}"); // When `position` is despawned, it is removed from all entities. // This ensured that dead components never exist world.despawn(position.id())?; tracing::info!("world: {world:#?}"); world.despawn(id)?; }
The meta
allows the user to provide a function to attach extra components to
the entity. This is used by the => [ty, ty]
syntax for the component
macro.
The world will automatically manage the lifetime of the component to ensure that no entity has invalid components attached to it.
Relations
As a component is just a normal entity you can add an entity to another entity. Such as adding a parent entity to the children entities.
However, while this method allows quick and easy entity hierarchies, there is no notion of what the entity represents, and no way to distinguish it from another component.
This is where component parameterization comes to play.
An entity is 64
bits in size, sufficient for holding the kind
, index
, and
generation
.
However, since the world manages the lifetime of the component, the generation
of 32
bits is freed up, which allows other data to be stored, such as another
entity id.
This allows the upper bits of a component(entity) id to contain another entity as the generation is not needed.
#![allow(unused)] fn main() { #[derive(Debug, Clone)] struct RelationData { // This allows you to add extra data to the child in the relation distance: f32, } let child_of = world.spawn_relation::<RelationData>("child_of", |desc| { let mut buf = ComponentBuffer::new(); <Debug as MetaData<RelationData>>::attach(desc, &mut buf); buf }); let parent = world.spawn(); let child = Entity::builder() .set(child_of(parent), RelationData { distance: 1.0 }) .spawn(&mut world); let data = world.get(child, child_of(parent))?; tracing::info!("Relation distance: {:?}", data.distance); drop(data); world.despawn(parent)?; assert!(world.get(child, child_of(parent)).is_err()); }
When despawning either the relation component or target entity, the "parent", the component is removed from all entities.