Shareable Components
One word: reference types
. No, wait...
You can easily share the same instance of a component among multiple entities using reference types. This allows you to efficiently share state and updates across entities.
This is especially useful for heavyweight objects that are expensive to create or update, such as large data structures.
SHARING MADE SIMPLE
To share a component, declare it as a reference type (e.g., a class
or record
, but not ) and add the same instance to multiple entities. Each entity will hold a reference to the same instance of the component.struct
You can, of course, still add reference type components only to a single entity, and not share them at all.
Sharing Components
public class SharedData
{
public int Value;
}
var sharedData = new SharedData { Value = 42 };
var entity1 = world.Spawn().Add(sharedData);
var entity2 = world.Spawn().Add(sharedData);
Both entity1
and entity2
now reference the same sharedData
instance. Modifying sharedData
affects both entities.
Querying Shared Components
Query shared components using the same syntax as regular components:
record SharedData(int Value) // a mutable record, could also be a class
{
public int Value { get; set; } = Value;
}
using var world = new World();
var stream = world.Query<SharedData>().Stream();
var sharedData = new SharedData(42); // shared instance
world.Entity().Add(sharedData).Spawn(5); // add it to 5 fresh entities
stream.For((ref SharedData data) =>
{
data.Value++; // increments value once for each entity in query!
Console.WriteLine(data.ToString());
});
sharedData.Value++; // increment outside of runner
Console.WriteLine();
stream.For((ref SharedData data) =>
{
Console.WriteLine(data.ToString());
});
SharedData { Value = 43 }
SharedData { Value = 44 }
SharedData { Value = 45 }
SharedData { Value = 46 }
SharedData { Value = 47 }
SharedData { Value = 48 }
SharedData { Value = 48 }
SharedData { Value = 48 }
SharedData { Value = 48 }
SharedData { Value = 48 }
Considerations
Shared components can positively impact performance by reducing memory usage and allowing trivial updates of shared state.
However, accessing shared components involves an indirection. The data on the heap isn't acked as tightly in memory. Iterating over many entities and components can be slower.
Fortunately, Queries that don't include reference Components in their Stream Types will not suffer from this indirection at all!
Shared components introduce some weak coupling between entities. Be cautious when modifying shared instances.
Be mindful of the lifecycle of shared components to avoid memory leaks.
Conclusion
Shareable components in fennecs allow efficient sharing of state and updates among entities. Use them judiciously to balance convenience and performance.