Systems for entities with multiple instances of same components #971
-
After failing to come up with a solution to a specific problem for a few hours, I thought a new discussion might be a good idea. I imagine we have two components: Position and Velocity. It's a relatively simple task to write a system that takes a Position and Velocity of an entity and automatically adds the velocity to that position. Now imagine that, for whatever reason, we needed the ability for entities to have multiple positions and velocities, and we wanted to be able to control which velocity affected which position. The documentation makes me understand that the only way to give multiple instances of identical component types to an entity is to use pairs. So let's assume the following example:
Given the entity above, how would we adjust our system so that only Positions and Velocities with matching identifiers in the second pair slot are processed together? Is this possible at all? So far, I've only found theoretical approaches using rules and variables, but nothing that would be compatible with queries. The only working solution for queries I found was to use a hard-coded identifiers, but that's not quite what I want since it'd require making a new system for each possible identifier. If this isn't possible to do with systems, is there an alternative solution to this specific problem? Or do you think the approach itself is already a bad idea, and this should be handled entirely differently? (Like moving each additional component instance to an entirely new entity, for example). |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
I usually don't work with C or C++ but I have some familiarity with the C API, here's an example I threw together: typedef struct { int x, y, z; } Position;
typedef struct { int x, y, z; } Velocity;
int main(int argc, char *argv[]) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t first = ecs_entity_init(world, &(ecs_entity_desc_t){ .name = "First" });
ecs_entity_t second = ecs_entity_init(world, &(ecs_entity_desc_t){ .name = "Second" });
ecs_entity_t entity_with_first = ecs_entity_init(world, &(ecs_entity_desc_t){ .name = "EntityWithFirst" });
ecs_set_id(world, entity_with_first, ecs_pair(ecs_id(Position), first), sizeof(Position), &(Position){ 10, 20, 30 });
ecs_set_id(world, entity_with_first, ecs_pair(ecs_id(Velocity), first), sizeof(Velocity), &(Velocity){ 1, 2, 3 });
ecs_entity_t entity_with_second = ecs_entity_init(world, &(ecs_entity_desc_t){ .name = "EntityWithSecond" });
ecs_set_id(world, entity_with_second, ecs_pair(ecs_id(Position), second), sizeof(Position), &(Position){ 20, 40, 60 });
ecs_set_id(world, entity_with_second, ecs_pair(ecs_id(Velocity), second), sizeof(Velocity), &(Velocity){ 2, 4, 6 });
ecs_entity_t entity_with_both = ecs_entity_init(world, &(ecs_entity_desc_t){ .name = "EntityWithBoth" });
ecs_set_id(world, entity_with_both, ecs_pair(ecs_id(Position), first), sizeof(Position), &(Position){ 10, 20, 30 });
ecs_set_id(world, entity_with_both, ecs_pair(ecs_id(Velocity), first), sizeof(Velocity), &(Velocity){ 1, 2, 3 });
ecs_set_id(world, entity_with_both, ecs_pair(ecs_id(Position), second), sizeof(Position), &(Position){ 20, 40, 60 });
ecs_set_id(world, entity_with_both, ecs_pair(ecs_id(Velocity), second), sizeof(Velocity), &(Velocity){ 2, 4, 6 });
ecs_rule_t *rule = ecs_rule(world, { .expr = "(Position, $id), (Velocity, $id)" });
ecs_iter_t it = ecs_rule_iter(world, rule);
while (ecs_rule_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
ecs_entity_t id = ecs_pair_second(world, ecs_field_id(&it, 1));
for (int i = 0; i < it.count; i++) {
Position pos = p[i];
Velocity vel = v[i];
printf("Matched entity: %s\n", ecs_entity_str(it.world, it.entities[i]));
printf("Matched id: %s\n", ecs_get_name(world, id));
printf(" Position: %d:%d:%d\n", pos.x, pos.y, pos.z);
printf(" Velocity: %d:%d:%d\n", vel.x, vel.y, vel.z);
}
}
} Here's the output. As you can see the entity with both "kinds" of Position and Velocity matches the query twice.
|
Beta Was this translation helpful? Give feedback.
-
This will be possible to do with queries (not just rules) & query variables, as queries that only use variables as targets of pairs can in theory be cached. It's on the roadmap but might take me a while to implement |
Beta Was this translation helpful? Give feedback.
This will be possible to do with queries (not just rules) & query variables, as queries that only use variables as targets of pairs can in theory be cached. It's on the roadmap but might take me a while to implement