Properly link flecs library

This commit is contained in:
2023-11-09 11:38:29 +01:00
parent dc585396c3
commit 8edcf9305c
1392 changed files with 390081 additions and 164 deletions

View File

@@ -0,0 +1,16 @@
#ifndef BASICS_H
#define BASICS_H
/* This generated file contains includes for project dependencies */
#include "basics/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef BASICS_BAKE_CONFIG_H
#define BASICS_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,12 @@
{
"id": "basics",
"type": "application",
"value": {
"author": "Jane Doe",
"description": "A simple hello world flecs application",
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,85 @@
#include <basics.h>
#include <stdio.h>
typedef struct {
double x;
double y;
} Position, Velocity;
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Position);
ECS_COMPONENT(ecs, Velocity);
// Create a query for Position, Velocity. Queries are the fastest way to
// iterate entities as they cache results.
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) },
{ .id = ecs_id(Velocity), .inout = EcsIn}
}
});
// Create a few test entities for a Position, Velocity query
ecs_entity_t e1 = ecs_new_entity(ecs, "e1");
ecs_set(ecs, e1, Position, {10, 20});
ecs_set(ecs, e1, Velocity, {1, 2});
ecs_entity_t e2 = ecs_new_entity(ecs, "e2");
ecs_set(ecs, e2, Position, {10, 20});
ecs_set(ecs, e2, Velocity, {3, 4});
// This entity will not match as it does not have Position, Velocity
ecs_entity_t e3 = ecs_new_entity(ecs, "e3");
ecs_set(ecs, e3, Position, {10, 20});
// Iterate entities matching the query
ecs_iter_t it = ecs_query_iter(ecs, q);
// Outer loop, iterates archetypes
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
const Velocity *v = ecs_field(&it, Velocity, 2);
// Inner loop, iterates entities in archetype
for (int i = 0; i < it.count; i ++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
printf("%s: {%f, %f}\n", ecs_get_name(ecs, it.entities[i]),
p[i].x, p[i].y);
}
}
// Filters are uncached queries. They are a bit slower to iterate but faster
// to create & have lower overhead as they don't have to maintain a cache.
ecs_filter_t *f = ecs_filter(ecs, {
.terms = {
{ .id = ecs_id(Position) },
{ .id = ecs_id(Velocity), .inout = EcsIn}
}
});
// Filter iteration looks the same as query iteration
it = ecs_filter_iter(ecs, f);
while (ecs_filter_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
const Velocity *v = ecs_field(&it, Velocity, 2);
for (int i = 0; i < it.count; i ++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
printf("%s: {%f, %f}\n", ecs_get_name(ecs, it.entities[i]),
p[i].x, p[i].y);
}
}
// Cleanup filter. Filters can allocate memory if the number of terms
// exceeds their internal buffer, or when terms have names. In this case the
// filter didn't allocate, so while fini isn't strictly necessary here, it's
// still good practice to add it.
ecs_filter_fini(f);
return ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef CHANGE_TRACKING_H
#define CHANGE_TRACKING_H
/* This generated file contains includes for project dependencies */
#include "change_tracking/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef CHANGE_TRACKING_BAKE_CONFIG_H
#define CHANGE_TRACKING_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "change_tracking",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,155 @@
#include <change_tracking.h>
#include <stdio.h>
// Queries have a builtin mechanism for tracking changes per matched table. This
// is a cheap way of eliminating redundant work, as many entities can be skipped
// with a single check.
//
// This example shows how to use change tracking in combination with a few other
// techniques, like using prefabs to store a single dirty state for multiple
// entities and instanced queries.
typedef struct {
bool value;
} Dirty;
typedef struct {
double x, y;
} Position;
int main(int argc, char *argv[]) {
ecs_world_t *world = ecs_init_w_args(argc, argv);
ECS_COMPONENT(world, Dirty);
ECS_COMPONENT(world, Position);
// Create a query that just reads a component. We'll use this query for
// change tracking. Change tracking for a query is automatically enabled
// when query::changed() is called.
// Each query has its own private dirty state which is reset only when the
// query is iterated.
ecs_query_t *q_read = ecs_query(world, {
.filter.terms = {{ .id = ecs_id(Position), .inout = EcsIn }}
});
// Create a query that writes the component based on a Dirty state.
ecs_query_t *q_write = ecs_query(world, {
.filter = {
.terms = {
// Only match if Dirty is shared from prefab
{
.id = ecs_id(Dirty),
.inout = EcsIn,
.src.flags = EcsUp
},
{ .id = ecs_id(Position) }
},
.instanced = true // Instanced iteration is faster (see example)
}
});
// Create two prefabs with a Dirty component. We can use this to share a
// single Dirty value for all entities in a table.
ecs_entity_t p1 = ecs_new_prefab(world, "p1");
ecs_set(world, p1, Dirty, {false});
ecs_entity_t p2 = ecs_new_prefab(world, "p2");
ecs_set(world, p2, Dirty, {true});
// Create instances of p1 and p2. Because the entities have different
// prefabs, they end up in different tables.
ecs_entity_t e1 = ecs_new_entity(world, "e1");
ecs_add_pair(world, e1, EcsIsA, p1);
ecs_set(world, e1, Position, {10, 20});
ecs_entity_t e2 = ecs_new_entity(world, "e2");
ecs_add_pair(world, e2, EcsIsA, p1);
ecs_set(world, e2, Position, {30, 40});
ecs_entity_t e3 = ecs_new_entity(world, "e3");
ecs_add_pair(world, e3, EcsIsA, p2);
ecs_set(world, e3, Position, {50, 60});
ecs_entity_t e4 = ecs_new_entity(world, "e4");
ecs_add_pair(world, e4, EcsIsA, p2);
ecs_set(world, e4, Position, {70, 80});
// We can use the changed() function on the query to check if any of the
// tables it is matched with has changed. Since this is the first time that
// we check this and the query is matched with the tables we just created,
// the function will return true.
printf("q_read changed: %d\n", ecs_query_changed(q_read, NULL));
// The changed state will remain true until we have iterated each table.
ecs_iter_t it = ecs_query_iter(world, q_read);
while (ecs_query_next(&it)) {
// With the it.changed() function we can check if the table we're
// currently iterating has changed since last iteration.
// Because this is the first time the query is iterated, all tables
// will show up as changed.
char *table_str = ecs_table_str(world, it.table);
printf("it.changed for table [%s]: %d\n", table_str,
ecs_query_changed(q_read, &it));
ecs_os_free(table_str);
}
// Now that we have iterated all tables, the dirty state is reset.
printf("q_read changed: %d\n\n", ecs_query_changed(q_read, NULL));
// Iterate the write query. Because the Position term is InOut (default)
// iterating the query will write to the dirty state of iterated tables.
it = ecs_query_iter(world, q_write);
while (ecs_query_next(&it)) {
Dirty *dirty = ecs_field(&it, Dirty, 1);
char *table_str = ecs_table_str(world, it.table);
printf("iterate table [%s]\n", table_str);
ecs_os_free(table_str);
// Because we enforced that Dirty is a shared component, we can check
// a single value for the entire table.
if (!dirty->value) {
ecs_query_skip(&it);
table_str = ecs_table_str(world, it.table);
printf("it.skip for table [%s]\n", table_str);
ecs_os_free(table_str);
continue;
}
Position *p = ecs_field(&it, Position, 2);
// For all other tables the dirty state will be set.
for (int i = 0; i < it.count; i ++) {
p[i].x ++;
p[i].y ++;
}
}
// One of the tables has changed, so q_read.changed() will return true
printf("\nq_read changed: %d\n", ecs_query_changed(q_read, NULL));
// When we iterate the read query, we'll see that one table has changed.
it = ecs_query_iter(world, q_read);
while (ecs_query_next(&it)) {
char *table_str = ecs_table_str(world, it.table);
printf("it.changed for table [%s]: %d\n", table_str,
ecs_query_changed(q_read, &it));
ecs_os_free(table_str);
}
// Output:
// q_read.changed(): 1
// it.changed() for table [Position, (Identifier,Name), (IsA,p1)]: 1
// it.changed() for table [Position, (Identifier,Name), (IsA,p2)]: 1
// q_read.changed(): 0
//
// iterate table [Position, (Identifier,Name), (IsA,p1)]
// it.skip() for table [Position, (Identifier,Name), (IsA,p1)]
// iterate table [Position, (Identifier,Name), (IsA,p2)]
//
// q_read.changed(): 1
// it.changed() for table [Position, (Identifier,Name), (IsA,p1)]: 0
// it.changed() for table [Position, (Identifier,Name), (IsA,p2)]: 1
return ecs_fini(world);
}

View File

@@ -0,0 +1,16 @@
#ifndef GROUP_BY_H
#define GROUP_BY_H
/* This generated file contains includes for project dependencies */
#include "group_by/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef GROUP_BY_BAKE_CONFIG_H
#define GROUP_BY_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "group_by",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,126 @@
#include <group_by.h>
#include <stdio.h>
// Group by is a feature of cached queries that allows applications to assign a
// group id to each matched table. Tables that are assigned the same group id
// are stored together in "groups". This ensures that when a query is iterated,
// tables that share a group are iterated together.
//
// Groups in the cache are ordered by group id, which ensures that tables with
// lower ids are iterated before table with higher ids. This is the same
// mechanism that is used by the cascade feature, which groups tables by depth
// in a relationship hierarchy.
//
// This makes groups a more efficient, though less granular mechanism for
// ordering entities. Order is maintained at the group level, which means that
// once a group is created, tables can get added and removed to the group
// with is an O(1) operation.
//
// Groups can also be used as an efficient filtering mechanism. See the
// group_iter example for more details.
typedef struct {
double x, y;
} Position;
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Position);
ECS_TAG(ecs, Tag); // Dummy tag to put entities in different tables
// Create a relationship to use for the group_by function. Tables will
// be assigned the relationship target as group id
ECS_TAG(ecs, Group);
// Targets for the relationship, which will be used as group ids.
ECS_TAG(ecs, First);
ECS_TAG(ecs, Second);
ECS_TAG(ecs, Third);
// Grouped query
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
},
// Group tables by the relationship target of the "Group" relationship.
// A custom group_by function can be provided to derive a group id from
// a table, see the group_by_custom example for more details.
.group_by_id = Group
});
// Create entities in 6 different tables with 3 group ids
ecs_entity_t e1 = ecs_new_w_pair(ecs, Group, Third);
ecs_set(ecs, e1, Position, {1, 1});
ecs_entity_t e2 = ecs_new_w_pair(ecs, Group, Second);
ecs_set(ecs, e2, Position, {2, 2});
ecs_entity_t e3 = ecs_new_w_pair(ecs, Group, First);
ecs_set(ecs, e3, Position, {3, 3});
ecs_entity_t e4 = ecs_new_w_pair(ecs, Group, Third);
ecs_set(ecs, e4, Position, {4, 4});
ecs_add(ecs, e4, Tag);
ecs_entity_t e5 = ecs_new_w_pair(ecs, Group, Second);
ecs_set(ecs, e5, Position, {5, 5});
ecs_add(ecs, e5, Tag);
ecs_entity_t e6 = ecs_new_w_pair(ecs, Group, First);
ecs_set(ecs, e6, Position, {6, 6});
ecs_add(ecs, e6, Tag);
// The query cache now looks like this:
// - group First:
// - table [Position, (Group, First)]
// - table [Postion, Tag, (Group, First)]
//
// - group Second:
// - table [Position, (Group, Second)]
// - table [Postion, Tag, (Group, Second)]
//
// - group Third:
// - table [Position, (Group, Third)]
// - table [Postion, Tag, (Group, Third)]
//
// Iterate query, print position & table components
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
char *table_str = ecs_table_str(ecs, it.table);
char *group_str = ecs_get_fullpath(ecs, it.group_id);
printf(" - group %s: table [%s]\n", group_str, table_str);
for (int i = 0; i < it.count; i ++) {
printf(" {%f, %f}\n", p[i].x, p[i].y);
}
ecs_os_free(group_str);
ecs_os_free(table_str);
printf("\n");
}
// Output:
// - group First: table [Position, (Group,First)]
// {3.000000, 3.000000}
//
// - group First: table [Position, Tag, (Group,First)]
// {6.000000, 6.000000}
//
// - group Second: table [Position, (Group,Second)]
// {2.000000, 2.000000}
//
// - group Second: table [Position, Tag, (Group,Second)]
// {5.000000, 5.000000}
//
// - group Third: table [Position, (Group,Third)]
// {1.000000, 1.000000}
//
// - group Third: table [Position, Tag, (Group,Third)]
// {4.000000, 4.000000}
return ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef GROUP_BY_CALLBACKS_H
#define GROUP_BY_CALLBACKS_H
/* This generated file contains includes for project dependencies */
#include "group_by_callbacks/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef GROUP_BY_CALLBACKS_BAKE_CONFIG_H
#define GROUP_BY_CALLBACKS_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "group_by_callbacks",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,168 @@
#include <group_by_callbacks.h>
#include <stdio.h>
#include <stdlib.h>
// This example shows how the on_group_create and on_group_delete callbacks can
// be used to get notified when a new group is registered for a query. These
// callbacks make it possible to associate and manage user data attached to
// groups.
typedef struct {
double x, y;
} Position;
// Custom type to associate with group
typedef struct {
int32_t counter;
} group_ctx;
int group_counter = 0;
// Callback invoked when a new group is created
static void* on_group_create(ecs_world_t *world,
uint64_t group_id, // id of the group that was created
void *group_by_arg) // group_by_ctx parameter in ecs_query_desc_t struct
{
(void)group_by_arg; // silence unused warning
printf("Group %s created\n", ecs_get_name(world, group_id));
// Return data that will be associated with the group
group_ctx *ctx = malloc(sizeof(group_ctx));
ctx->counter = ++ group_counter;
return ctx;
}
// Callback invoked when a group is deleted
static void on_group_delete(ecs_world_t *world,
uint64_t group_id, // id of the group that was deleted
void *ctx, // group context
void *group_by_arg) // group_by_ctx parameter in ecs_query_desc_t struct
{
(void)group_by_arg; // silence unused warning
printf("Group %s deleted\n", ecs_get_name(world, group_id));
// Free data associated with group
free(ctx);
}
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Position);
ECS_TAG(ecs, Tag); // Dummy tag to put entities in different tables
// Create a relationship to use for the group_by function. Tables will
// be assigned the relationship target as group id
ECS_TAG(ecs, Group);
// Targets for the relationship, which will be used as group ids.
ECS_TAG(ecs, First);
ECS_TAG(ecs, Second);
ECS_TAG(ecs, Third);
// Grouped query
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
},
.group_by_id = Group,
.on_group_create = on_group_create,
.on_group_delete = on_group_delete
});
// Create entities in 6 different tables with 3 group ids
ecs_entity_t e1 = ecs_new_w_pair(ecs, Group, Third);
ecs_set(ecs, e1, Position, {1, 1});
ecs_entity_t e2 = ecs_new_w_pair(ecs, Group, Second);
ecs_set(ecs, e2, Position, {2, 2});
ecs_entity_t e3 = ecs_new_w_pair(ecs, Group, First);
ecs_set(ecs, e3, Position, {3, 3});
ecs_entity_t e4 = ecs_new_w_pair(ecs, Group, Third);
ecs_set(ecs, e4, Position, {4, 4});
ecs_add(ecs, e4, Tag);
ecs_entity_t e5 = ecs_new_w_pair(ecs, Group, Second);
ecs_set(ecs, e5, Position, {5, 5});
ecs_add(ecs, e5, Tag);
ecs_entity_t e6 = ecs_new_w_pair(ecs, Group, First);
ecs_set(ecs, e6, Position, {6, 6});
ecs_add(ecs, e6, Tag);
// The query cache now looks like this:
// - group First:
// - table [Position, (Group, First)]
// - table [Postion, Tag, (Group, First)]
//
// - group Second:
// - table [Position, (Group, Second)]
// - table [Postion, Tag, (Group, Second)]
//
// - group Third:
// - table [Position, (Group, Third)]
// - table [Postion, Tag, (Group, Third)]
//
printf("\n");
// Iterate query, print position & table components
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
char *table_str = ecs_table_str(ecs, it.table);
char *group_str = ecs_get_fullpath(ecs, it.group_id);
group_ctx *ctx = ecs_query_get_group_ctx(q, it.group_id);
printf(" - group %s: table [%s]\n", group_str, table_str);
printf(" counter: %d\n", ctx->counter);
for (int i = 0; i < it.count; i ++) {
printf(" {%f, %f}\n", p[i].x, p[i].y);
}
ecs_os_free(group_str);
ecs_os_free(table_str);
printf("\n");
}
// Deleting the query will call the on_group_deleted callback
ecs_query_fini(q);
// Output:
// Group Third created
// Group Second created
// Group First created
//
// - group First: table [Position, (Group,First)]
// counter: 3
// {3.000000, 3.000000}
//
// - group First: table [Position, Tag, (Group,First)]
// counter: 3
// {6.000000, 6.000000}
//
// - group Second: table [Position, (Group,Second)]
// counter: 2
// {2.000000, 2.000000}
//
// - group Second: table [Position, Tag, (Group,Second)]
// counter: 2
// {5.000000, 5.000000}
//
// - group Third: table [Position, (Group,Third)]
// counter: 1
// {1.000000, 1.000000}
//
// - group Third: table [Position, Tag, (Group,Third)]
// counter: 1
// {4.000000, 4.000000}
//
// Group First deleted
// Group Third deleted
// Group Second deleted
return ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef GROUP_BY_CUSTOM_H
#define GROUP_BY_CUSTOM_H
/* This generated file contains includes for project dependencies */
#include "group_by_custom/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef GROUP_BY_CUSTOM_BAKE_CONFIG_H
#define GROUP_BY_CUSTOM_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "group_by_custom",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,124 @@
#include <group_by_custom.h>
#include <stdio.h>
// This example does the same as the group_by example, but with a custom
// group_by function. A custom function makes it possible to customize how a
// group id is calculated for a table.
typedef struct {
double x, y;
} Position;
uint64_t group_by_relation(ecs_world_t *ecs, ecs_table_t *table,
ecs_entity_t id, void *ctx)
{
(void)ctx; // marks ctx as unused, avoids compiler warnings
// Use ecs_search to find the target for the relationship in the table
ecs_id_t match;
if (ecs_search(ecs, table, ecs_pair(id, EcsWildcard), &match) != -1) {
return ecs_pair_second(ecs, match); // First, Second or Third
}
return 0;
}
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Position);
ECS_TAG(ecs, Tag); // Dummy tag to put entities in different tables
// Create a relationship to use for the group_by function. Tables will
// be assigned the relationship target as group id
ECS_TAG(ecs, Group);
// Targets for the relationship, which will be used as group ids.
ECS_TAG(ecs, First);
ECS_TAG(ecs, Second);
ECS_TAG(ecs, Third);
// Grouped query
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
},
.group_by = group_by_relation,
.group_by_id = Group // Passed to id argument of group_by function
});
// Create entities in 6 different tables with 3 group ids
ecs_entity_t e1 = ecs_new_w_pair(ecs, Group, Third);
ecs_set(ecs, e1, Position, {1, 1});
ecs_entity_t e2 = ecs_new_w_pair(ecs, Group, Second);
ecs_set(ecs, e2, Position, {2, 2});
ecs_entity_t e3 = ecs_new_w_pair(ecs, Group, First);
ecs_set(ecs, e3, Position, {3, 3});
ecs_entity_t e4 = ecs_new_w_pair(ecs, Group, Third);
ecs_set(ecs, e4, Position, {4, 4});
ecs_add(ecs, e4, Tag);
ecs_entity_t e5 = ecs_new_w_pair(ecs, Group, Second);
ecs_set(ecs, e5, Position, {5, 5});
ecs_add(ecs, e5, Tag);
ecs_entity_t e6 = ecs_new_w_pair(ecs, Group, First);
ecs_set(ecs, e6, Position, {6, 6});
ecs_add(ecs, e6, Tag);
// The query cache now looks like this:
// - group First:
// - table [Position, (Group, First)]
// - table [Postion, Tag, (Group, First)]
//
// - group Second:
// - table [Position, (Group, Second)]
// - table [Postion, Tag, (Group, Second)]
//
// - group Third:
// - table [Position, (Group, Third)]
// - table [Postion, Tag, (Group, Third)]
//
// Iterate query, print position & table components
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
char *table_str = ecs_table_str(ecs, it.table);
char *group_str = ecs_get_fullpath(ecs, it.group_id);
printf(" - group %s: table [%s]\n", group_str, table_str);
for (int i = 0; i < it.count; i ++) {
printf(" {%f, %f}\n", p[i].x, p[i].y);
}
ecs_os_free(group_str);
ecs_os_free(table_str);
printf("\n");
}
// Output:
// - group First: table [Position, (Group,First)]
// {3.000000, 3.000000}
//
// - group First: table [Position, Tag, (Group,First)]
// {6.000000, 6.000000}
//
// - group Second: table [Position, (Group,Second)]
// {2.000000, 2.000000}
//
// - group Second: table [Position, Tag, (Group,Second)]
// {5.000000, 5.000000}
//
// - group Third: table [Position, (Group,Third)]
// {1.000000, 1.000000}
//
// - group Third: table [Position, Tag, (Group,Third)]
// {4.000000, 4.000000}
return ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef GROUP_ITER_H
#define GROUP_ITER_H
/* This generated file contains includes for project dependencies */
#include "group_iter/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef GROUP_ITER_BAKE_CONFIG_H
#define GROUP_ITER_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "group_iter",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,132 @@
#include <group_iter.h>
#include <stdio.h>
// A group iterator iterates over a single group of a grouped query (see the
// group_by example for more details). This can be useful when an application
// may need to match different entities based on the context of the game, such
// as editor mode, day/night, inside/outside or location in the world.
//
// One example is that of an open game which is divided up into world
// cells. Even though a world may contain many entities, only the entities in
// cells close to the player need to be processed.
//
// Instead of creating a cached query per world cell, which could be expensive
// as there are more caches to keep in sync, applications can create a single
// query grouped by world cell, and use group iterators to only iterate the
// necessary cells.
uint64_t group_by_relation(ecs_world_t *ecs, ecs_table_t *table,
ecs_entity_t id, void *ctx)
{
(void)ctx; // marks ctx as unused, avoids compiler warnings
// Use ecs_search to find the target for the relationship in the table
ecs_id_t match;
if (ecs_search(ecs, table, ecs_pair(id, EcsWildcard), &match) != -1) {
return ecs_pair_second(ecs, match); // World cell is 2nd element of pair
}
return 0;
}
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
// A world cell relationship with four cells
ECS_TAG(ecs, WorldCell);
ECS_TAG(ecs, Cell_0_0);
ECS_TAG(ecs, Cell_0_1);
ECS_TAG(ecs, Cell_1_0);
ECS_TAG(ecs, Cell_1_1);
// Npc tags
ECS_TAG(ecs, Npc);
ECS_TAG(ecs, Merchant);
ECS_TAG(ecs, Soldier);
ECS_TAG(ecs, Beggar);
ECS_TAG(ecs, Mage);
// Create Npcs in world cell 0_0
ecs_entity_t npc_01 = ecs_new_w_pair(ecs, WorldCell, Cell_0_0);
ecs_add(ecs, npc_01, Merchant);
ecs_add(ecs, npc_01, Npc);
ecs_entity_t npc_02 = ecs_new_w_pair(ecs, WorldCell, Cell_0_0);
ecs_add(ecs, npc_02, Merchant);
ecs_add(ecs, npc_02, Npc);
// Create Npcs in world cell 0_1
ecs_entity_t npc_03 = ecs_new_w_pair(ecs, WorldCell, Cell_0_1);
ecs_add(ecs, npc_03, Beggar);
ecs_add(ecs, npc_03, Npc);
ecs_entity_t npc_04 = ecs_new_w_pair(ecs, WorldCell, Cell_0_1);
ecs_add(ecs, npc_04, Soldier);
ecs_add(ecs, npc_04, Npc);
// Create Npcs in world cell 1_0
ecs_entity_t npc_05 = ecs_new_w_pair(ecs, WorldCell, Cell_1_0);
ecs_add(ecs, npc_05, Mage);
ecs_add(ecs, npc_05, Npc);
ecs_entity_t npc_06 = ecs_new_w_pair(ecs, WorldCell, Cell_1_0);
ecs_add(ecs, npc_06, Beggar);
ecs_add(ecs, npc_06, Npc);
// Create Npcs in world cell 1_1
ecs_entity_t npc_07 = ecs_new_w_pair(ecs, WorldCell, Cell_1_1);
ecs_add(ecs, npc_07, Soldier);
ecs_add(ecs, npc_07, Npc);
// Create a query that matches all Npc's, grouped by WorldCell
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = Npc }
},
.group_by = group_by_relation,
.group_by_id = WorldCell
});
// Iterate all tables
printf("All tables:\n");
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
char *table_str = ecs_table_str(ecs, it.table);
char *group_str = ecs_get_fullpath(ecs, it.group_id);
printf(" - group %s: table [%s]\n", group_str, table_str);
// Uncomment to iterate entities in table
// for (int i = 0; i < it.count; i ++) { }
ecs_os_free(group_str);
ecs_os_free(table_str);
}
printf("\n");
// Only iterate entities in cell 1_0
printf("Tables for cell 1_0:\n");
it = ecs_query_iter(ecs, q);
ecs_query_set_group(&it, Cell_1_0);
while (ecs_query_next(&it)) {
char *table_str = ecs_table_str(ecs, it.table);
char *group_str = ecs_get_fullpath(ecs, it.group_id);
printf(" - group %s: table [%s]\n", group_str, table_str);
ecs_os_free(group_str);
ecs_os_free(table_str);
}
// Output:
// All tables:
// - group Cell_0_0: table [Npc, Merchant, (WorldCell,Cell_0_0)]
// - group Cell_0_1: table [Npc, Beggar, (WorldCell,Cell_0_1)]
// - group Cell_0_1: table [Npc, Soldier, (WorldCell,Cell_0_1)]
// - group Cell_1_0: table [Npc, Mage, (WorldCell,Cell_1_0)]
// - group Cell_1_0: table [Npc, Beggar, (WorldCell,Cell_1_0)]
// - group Cell_1_1: table [Npc, Soldier, (WorldCell,Cell_1_1)]
//
// Tables for cell 1_0:
// - group Cell_1_0: table [Npc, Mage, (WorldCell,Cell_1_0)]
// - group Cell_1_0: table [Npc, Beggar, (WorldCell,Cell_1_0)]
return ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef HIERARCHIES_H
#define HIERARCHIES_H
/* This generated file contains includes for project dependencies */
#include "hierarchies/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef HIERARCHIES_BAKE_CONFIG_H
#define HIERARCHIES_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,12 @@
{
"id": "hierarchies",
"type": "application",
"value": {
"author": "Jane Doe",
"description": "A simple hello world flecs application",
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,96 @@
#include <hierarchies.h>
#include <stdio.h>
typedef struct {
double x;
double y;
} Position;
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Position);
// Tags for local/ecs position
ECS_TAG(ecs, Local);
ECS_TAG(ecs, World);
// Create a hierarchy. For an explanation see the entities/hierarchy example
ecs_entity_t sun = ecs_new_entity(ecs, "Sun");
ecs_add_pair(ecs, sun, ecs_id(Position), World);
ecs_set_pair(ecs, sun, Position, Local, {1, 1});
ecs_entity_t mercury = ecs_new_entity(ecs, "Mercury");
ecs_add_pair(ecs, mercury, EcsChildOf, sun);
ecs_add_pair(ecs, mercury, ecs_id(Position), World);
ecs_set_pair(ecs, mercury, Position, Local, {1, 1});
ecs_entity_t venus = ecs_new_entity(ecs, "Venus");
ecs_add_pair(ecs, venus, EcsChildOf, sun);
ecs_add_pair(ecs, venus, ecs_id(Position), World);
ecs_set_pair(ecs, venus, Position, Local, {2, 2});
ecs_entity_t earth = ecs_new_entity(ecs, "Earth");
ecs_add_pair(ecs, earth, EcsChildOf, sun);
ecs_add_pair(ecs, earth, ecs_id(Position), World);
ecs_set_pair(ecs, earth, Position, Local, {3, 3});
ecs_entity_t moon = ecs_new_entity(ecs, "Moon");
ecs_add_pair(ecs, moon, EcsChildOf, earth);
ecs_add_pair(ecs, moon, ecs_id(Position), World);
ecs_set_pair(ecs, moon, Position, Local, {0.1, 0.1});
// Create a hierarchical query to compute the global position from the
// local position and the parent position.
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
// Read from entity's Local position
{ .id = ecs_pair(ecs_id(Position), Local), .inout = EcsIn },
// Write to entity's World position
{ .id = ecs_pair(ecs_id(Position), World), .inout = EcsOut },
// Read from parent's World position
{
.id = ecs_pair(ecs_id(Position), World),
.inout = EcsIn,
// Get from the parent, in breadth-first order (cascade)
.src.flags = EcsParent | EcsCascade,
// Make parent term optional so we also match the root (sun)
.oper = EcsOptional
}
}
});
// Do the transform
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
const Position *p = ecs_field(&it, Position, 1);
Position *p_out = ecs_field(&it, Position, 2);
const Position *p_parent = ecs_field(&it, Position, 3);
// Inner loop, iterates entities in archetype
for (int i = 0; i < it.count; i ++) {
p_out[i].x = p[i].x;
p_out[i].y = p[i].y;
if (p_parent) {
p_out[i].x += p_parent->x;
p_out[i].y += p_parent->y;
}
}
}
// Print ecs positions
it = ecs_term_iter(ecs, &(ecs_term_t) {
.id = ecs_pair(ecs_id(Position), World)
});
while (ecs_term_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
for (int i = 0; i < it.count; i ++) {
printf("%s: {%f, %f}\n", ecs_get_name(ecs, it.entities[i]),
p[i].x, p[i].y);
}
}
return ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef INSTANCING_H
#define INSTANCING_H
/* This generated file contains includes for project dependencies */
#include "instancing/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef INSTANCING_BAKE_CONFIG_H
#define INSTANCING_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "instancing",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,116 @@
#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}
}

View File

@@ -0,0 +1,16 @@
#ifndef SINGLETON_H
#define SINGLETON_H
/* This generated file contains includes for project dependencies */
#include "singleton/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef SINGLETON_BAKE_CONFIG_H
#define SINGLETON_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,9 @@
{
"id": "singleton",
"type": "application",
"value": {
"use": [
"flecs"
]
}
}

View File

@@ -0,0 +1,71 @@
#include <singleton.h>
#include <stdio.h>
// This example shows how to use singleton components in queries.
// Singleton component
typedef struct {
double value;
} Gravity;
// Entity component
typedef struct {
double x, y;
} Velocity;
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Gravity);
ECS_COMPONENT(ecs, Velocity);
// Set singleton
ecs_singleton_set(ecs, Gravity, { 9.81 });
ecs_entity_t e1 = ecs_new_entity(ecs, "e1");
ecs_entity_t e2 = ecs_new_entity(ecs, "e2");
ecs_entity_t e3 = ecs_new_entity(ecs, "e3");
// Set Velocity
ecs_set(ecs, e1, Velocity, {0, 0});
ecs_set(ecs, e2, Velocity, {0, 1});
ecs_set(ecs, e3, Velocity, {0, 2});
// Create query that matches Gravity as singleton
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Velocity) },
// A singleton is a component matched on itself
{ .id = ecs_id(Gravity), .src.id = ecs_id(Gravity) }
},
// Optional, but lets us iterate entities in bulk even though the query
// returns fields with mixed counts (see query manual).
.filter.instanced = true
});
// In a query string expression you can use the $ shortcut for singletons:
// Velocity, Gravity($)
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
Velocity *v = ecs_field(&it, Velocity, 1);
Gravity *g = ecs_field(&it, Gravity, 2);
for (int i = 0; i < it.count; i ++) {
// Make sure to access g as a pointer, as we only have a single
// instance of the Gravity component.
v[i].y += g->value;
printf("%s velocity is {%f, %f}\n",
ecs_get_name(ecs, it.entities[i]), v[i].x, v[i].y);
}
}
// Output
// e1 velocity is {0.000000, 9.810000}
// e2 velocity is {0.000000, 10.810000}
// e3 velocity is {0.000000, 11.810000}
ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef SORTING_H
#define SORTING_H
/* This generated file contains includes for project dependencies */
#include "sorting/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef SORTING_BAKE_CONFIG_H
#define SORTING_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "sorting",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,104 @@
#include <sorting.h>
#include <stdio.h>
typedef struct {
double x, y;
} Position;
// Order by x member of Position */
int compare_position(
ecs_entity_t e1,
const Position *p1,
ecs_entity_t e2,
const Position *p2)
{
(void)e1;
(void)e2;
return (p1->x > p2->x) - (p1->x < p2->x);
}
void print_position(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
for (int i = 0; i < it->count; i ++) {
printf("{%.1f, %.1f}\n", p[i].x, p[i].y);
}
}
// Iterate query, printed values will be ordered
void print_query(ecs_world_t *ecs, ecs_query_t *q) {
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
print_position(&it);
}
}
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Position);
ecs_entity_t e = ecs_set(ecs, 0, Position, {1, 0});
ecs_set(ecs, 0, Position, {6, 0});
ecs_set(ecs, 0, Position, {2, 0});
ecs_set(ecs, 0, Position, {5, 0});
ecs_set(ecs, 0, Position, {4, 0});
// Create a sorted system
ecs_entity_t sys = ecs_system(ecs, {
.query = {
.filter.terms = {{ .id = ecs_id(Position) }},
.order_by = (ecs_order_by_action_t)compare_position,
.order_by_component = ecs_id(Position)
},
.callback = print_position
});
// Create sorted query
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {{ .id = ecs_id(Position) }},
.order_by = (ecs_order_by_action_t)compare_position,
.order_by_component = ecs_id(Position)
});
// Iterate query, print values of Position
printf("-- First iteration\n");
print_query(ecs, q);
// Change the value of one entity, invalidating the order
ecs_set(ecs, e, Position, {7, 0});
// Iterate query again, printed values are still ordered
printf("\n-- Second iteration\n");
print_query(ecs, q);
// Create new entity to show that data is also sorted for system
ecs_set(ecs, 0, Position, {3, 0});
printf("\n-- System iteration\n");
ecs_run(ecs, sys, 0, NULL);
// Output
// -- First iteration
// {1.0, 0.0}
// {2.0, 0.0}
// {4.0, 0.0}
// {5.0, 0.0}
// {6.0, 0.0}
//
// -- Second iteration
// {2.0, 0.0}
// {4.0, 0.0}
// {5.0, 0.0}
// {6.0, 0.0}
// {7.0, 0.0}
//
// -- System iteration
// {2.0, 0.0}
// {3.0, 0.0}
// {4.0, 0.0}
// {5.0, 0.0}
// {6.0, 0.0}
// {7.0, 0.0}
return ecs_fini(ecs);
}

View File

@@ -0,0 +1,16 @@
#ifndef WILDCARDS_H
#define WILDCARDS_H
/* This generated file contains includes for project dependencies */
#include "wildcards/bake_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */
#ifndef WILDCARDS_BAKE_CONFIG_H
#define WILDCARDS_BAKE_CONFIG_H
/* Headers of public dependencies */
#include <flecs.h>
#endif

View File

@@ -0,0 +1,10 @@
{
"id": "wildcards",
"type": "application",
"value": {
"use": [
"flecs"
],
"public": false
}
}

View File

@@ -0,0 +1,50 @@
#include <wildcards.h>
#include <stdio.h>
// Queries can have wildcard terms that can match multiple instances of a
// relationship or relationship target.
typedef struct {
int amount;
} Eats;
int main(int argc, char *argv[]) {
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
ECS_COMPONENT(ecs, Eats);
ECS_TAG(ecs, Apples);
ECS_TAG(ecs, Pears);
// Create a query that matches edible components
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {{ .id = ecs_pair(ecs_id(Eats), EcsWildcard ) }}
});
// Create a few entities that match the query
ecs_entity_t bob = ecs_new_entity(ecs, "Bob");
ecs_set_pair(ecs, bob, Eats, Apples, {10});
ecs_set_pair(ecs, bob, Eats, Pears, {5});
ecs_entity_t alice = ecs_new_entity(ecs, "Alice");
ecs_set_pair(ecs, alice, Eats, Apples, {4});
// Iterate the query
ecs_iter_t it = ecs_query_iter(ecs, q);
while (ecs_query_next(&it)) {
Eats *eats = ecs_field(&it, Eats, 1);
ecs_id_t pair = ecs_field_id(&it, 1);
ecs_entity_t food = ecs_pair_second(ecs, pair);
for (int i = 0; i < it.count; i ++) {
printf("%s eats %d %s\n", ecs_get_name(ecs, it.entities[i]),
eats[i].amount, ecs_get_name(ecs, food));
}
}
// Output:
// Bob eats 10 Apples
// Bob eats 5 Pears
// Alice eats 4 Apples
return ecs_fini(ecs);
}