Properly link flecs library
This commit is contained in:
16
engine/libs/flecs/examples/c/queries/basics/include/basics.h
Normal file
16
engine/libs/flecs/examples/c/queries/basics/include/basics.h
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
12
engine/libs/flecs/examples/c/queries/basics/project.json
Normal file
12
engine/libs/flecs/examples/c/queries/basics/project.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "basics",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"author": "Jane Doe",
|
||||
"description": "A simple hello world flecs application",
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
85
engine/libs/flecs/examples/c/queries/basics/src/main.c
Normal file
85
engine/libs/flecs/examples/c/queries/basics/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "change_tracking",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
155
engine/libs/flecs/examples/c/queries/change_tracking/src/main.c
Normal file
155
engine/libs/flecs/examples/c/queries/change_tracking/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
10
engine/libs/flecs/examples/c/queries/group_by/project.json
Normal file
10
engine/libs/flecs/examples/c/queries/group_by/project.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "group_by",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
126
engine/libs/flecs/examples/c/queries/group_by/src/main.c
Normal file
126
engine/libs/flecs/examples/c/queries/group_by/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "group_by_callbacks",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "group_by_custom",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
124
engine/libs/flecs/examples/c/queries/group_by_custom/src/main.c
Normal file
124
engine/libs/flecs/examples/c/queries/group_by_custom/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
10
engine/libs/flecs/examples/c/queries/group_iter/project.json
Normal file
10
engine/libs/flecs/examples/c/queries/group_iter/project.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "group_iter",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
132
engine/libs/flecs/examples/c/queries/group_iter/src/main.c
Normal file
132
engine/libs/flecs/examples/c/queries/group_iter/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "hierarchies",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"author": "Jane Doe",
|
||||
"description": "A simple hello world flecs application",
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
96
engine/libs/flecs/examples/c/queries/hierarchies/src/main.c
Normal file
96
engine/libs/flecs/examples/c/queries/hierarchies/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
10
engine/libs/flecs/examples/c/queries/instancing/project.json
Normal file
10
engine/libs/flecs/examples/c/queries/instancing/project.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "instancing",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
116
engine/libs/flecs/examples/c/queries/instancing/src/main.c
Normal file
116
engine/libs/flecs/examples/c/queries/instancing/src/main.c
Normal 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}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"id": "singleton",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
]
|
||||
}
|
||||
}
|
||||
71
engine/libs/flecs/examples/c/queries/singleton/src/main.c
Normal file
71
engine/libs/flecs/examples/c/queries/singleton/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
10
engine/libs/flecs/examples/c/queries/sorting/project.json
Normal file
10
engine/libs/flecs/examples/c/queries/sorting/project.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "sorting",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
104
engine/libs/flecs/examples/c/queries/sorting/src/main.c
Normal file
104
engine/libs/flecs/examples/c/queries/sorting/src/main.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
10
engine/libs/flecs/examples/c/queries/wildcards/project.json
Normal file
10
engine/libs/flecs/examples/c/queries/wildcards/project.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "wildcards",
|
||||
"type": "application",
|
||||
"value": {
|
||||
"use": [
|
||||
"flecs"
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
}
|
||||
50
engine/libs/flecs/examples/c/queries/wildcards/src/main.c
Normal file
50
engine/libs/flecs/examples/c/queries/wildcards/src/main.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user