Files
PixelDefense/engine/libs/flecs/examples/c/queries/instancing/src/main.c

117 lines
4.6 KiB
C

#include <instancing.h>
#include <stdio.h>
/* Instancing is the ability of queries to iterate results with fields that have
* different numbers of elements. The term "instancing" is borrowed from
* graphics APIs, where it means reusing the same data for multiple "instances".
*
* Query instancing works in much the same way. By default queries match all
* components on the same entity. It is however possible to request data from
* other entities, like getting the Position from the entity's parent.
*
* Instancing refers to the ability of queries to iterate components for
* multiple entities while at the same time providing "instanced" components,
* which are always provided one element at a time.
*
* Instancing is often used in combination with parent-child relationships and
* prefabs, but is applicable to any kind of query where some of the terms are
* matched on N entities, and some on a single entity.
*
* By default queries are not instanced, which means that if a result contains
* mixed fields, entities will be iterated one by one instead of in batches.
* This is safer, as code doesn't have to do anything different for owned and
* shared fields, but does come at a performance penalty.
*
* The each() iterator function always uses an instanced iterator under the
* hood. This is transparent to the application, but improves performance. For
* this reason using each() can be faster than using uninstanced iter().
*/
typedef struct {
double x, y;
} Position, Velocity;
int main(int argc, char *argv[]) {
ecs_world_t *world = ecs_init_w_args(argc, argv);
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
// Create a query for Position, Velocity. We'll create a few entities that
// have Velocity as owned and shared component.
ecs_query_t *q = ecs_query(world, {
.filter = {
.terms = {
// Position must always be owned by the entity
{ .id = ecs_id(Position), .src.flags = EcsSelf },
{ .id = ecs_id(Velocity) } // Velocity may be shared (default)
},
.instanced = true
}
});
// Create a prefab with Velocity. Prefabs are not matched with queries.
ecs_entity_t prefab = ecs_new_prefab(world, "p");
ecs_set(world, prefab, Velocity, {1, 2});
// Create a few entities that own Position & share Velocity from the prefab.
ecs_entity_t e1 = ecs_new_entity(world, "e1");
ecs_add_pair(world, e1, EcsIsA, prefab);
ecs_set(world, e1, Position, {10, 20});
ecs_entity_t e2 = ecs_new_entity(world, "e2");
ecs_add_pair(world, e2, EcsIsA, prefab);
ecs_set(world, e2, Position, {10, 20});
// Create a few entities that own all components
ecs_entity_t e3 = ecs_new_entity(world, "e3");
ecs_set(world, e3, Position, {10, 20});
ecs_set(world, e3, Velocity, {3, 4});
ecs_entity_t e4 = ecs_new_entity(world, "e4");
ecs_set(world, e4, Position, {10, 20});
ecs_set(world, e4, Velocity, {4, 5});
// Iterate the instanced query. Note how when a query is instanced, it needs
// to check whether a field is owned or not in order to know how to access
// it. In the case of an owned field it is iterated as an array, whereas
// in the case of a shared field, it is accessed as a pointer.
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
// Check if Velocity is owned, in which case it's accessed as array.
// Position will always be owned, since we set the term to Self.
if (ecs_field_is_self(&it, 2)) { // Velocity is term 2
printf("Velocity is owned\n");
for (int i = 0; i < it.count; i ++) {
// If Velocity is shared, access the field as an array.
p[i].x += v[i].x;
p[i].y += v[i].y;
printf("%s: {%f, %f}\n", ecs_get_name(it.world, it.entities[i]),
p[i].x, p[i].y);
}
} else {
printf("Velocity is shared\n");
for (int i = 0; i < it.count; i ++) {
// If Velocity is shared, access the field as a pointer.
p[i].x += v->x;
p[i].y += v->y;
printf("%s: {%f, %f}\n", ecs_get_name(it.world, it.entities[i]),
p[i].x, p[i].y);
}
}
}
return ecs_fini(world);
// Output
// Velocity is shared
// e1: {11.000000, 22.000000}
// e2: {11.000000, 22.000000}
// Velocity is owned
// e3: {13.000000, 24.000000}
// e4: {14.000000, 25.000000}
}