![]() |
Flecs v3.2
A fast entity component system (ECS) for C & C++
|
Functions for working with ecs_query_t
.
More...
Classes | |
struct | ecs_query_desc_t |
Used with ecs_query_init. More... | |
Typedefs | |
typedef struct ecs_query_desc_t | ecs_query_desc_t |
Used with ecs_query_init. | |
Functions | |
ecs_query_t * | ecs_query_init (ecs_world_t *world, const ecs_query_desc_t *desc) |
Create a query. More... | |
void | ecs_query_fini (ecs_query_t *query) |
Destroy a query. More... | |
const ecs_filter_t * | ecs_query_get_filter (const ecs_query_t *query) |
Get filter from a query. More... | |
ecs_iter_t | ecs_query_iter (const ecs_world_t *world, ecs_query_t *query) |
Return a query iterator. More... | |
bool | ecs_query_next (ecs_iter_t *iter) |
Progress the query iterator. More... | |
bool | ecs_query_next_instanced (ecs_iter_t *iter) |
Same as ecs_query_next, but always instanced. More... | |
bool | ecs_query_next_table (ecs_iter_t *iter) |
Fast alternative to ecs_query_next that only returns matched tables. More... | |
int | ecs_query_populate (ecs_iter_t *iter, bool when_changed) |
Populate iterator fields. More... | |
bool | ecs_query_changed (ecs_query_t *query, const ecs_iter_t *it) |
Returns whether the query data changed since the last iteration. More... | |
void | ecs_query_skip (ecs_iter_t *it) |
Skip a table while iterating. More... | |
void | ecs_query_set_group (ecs_iter_t *it, uint64_t group_id) |
Set group to iterate for query iterator. More... | |
void * | ecs_query_get_group_ctx (const ecs_query_t *query, uint64_t group_id) |
Get context of query group. More... | |
const ecs_query_group_info_t * | ecs_query_get_group_info (const ecs_query_t *query, uint64_t group_id) |
Get information about query group. More... | |
bool | ecs_query_orphaned (const ecs_query_t *query) |
Returns whether query is orphaned. More... | |
char * | ecs_query_str (const ecs_query_t *query) |
Convert query to string. More... | |
int32_t | ecs_query_table_count (const ecs_query_t *query) |
Returns number of tables query matched with. More... | |
int32_t | ecs_query_empty_table_count (const ecs_query_t *query) |
Returns number of empty tables query matched with. More... | |
int32_t | ecs_query_entity_count (const ecs_query_t *query) |
Returns number of entities query matched with. More... | |
void * | ecs_query_get_ctx (const ecs_query_t *query) |
Get query ctx. More... | |
void * | ecs_query_get_binding_ctx (const ecs_query_t *query) |
Get query binding ctx. More... | |
Functions for working with ecs_query_t
.
bool ecs_query_changed | ( | ecs_query_t * | query, |
const ecs_iter_t * | it | ||
) |
Returns whether the query data changed since the last iteration.
The operation will return true after:
The operation will not return true after a write-only (EcsOut) or filter (EcsInOutNone) term has changed, when a term is not matched with the current table (This subject) or for tag terms.
The changed state of a table is reset after it is iterated. If a iterator was not iterated until completion, tables may still be marked as changed.
If no iterator is provided the operation will return the changed state of the all matched tables of the query.
If an iterator is provided, the operation will return the changed state of the currently returned iterator result. The following preconditions must be met before using an iterator with change detection:
query | The query (optional if 'it' is provided). |
it | The iterator result to test (optional if 'query' is provided). |
int32_t ecs_query_empty_table_count | ( | const ecs_query_t * | query | ) |
Returns number of empty tables query matched with.
query | The query. |
int32_t ecs_query_entity_count | ( | const ecs_query_t * | query | ) |
Returns number of entities query matched with.
This operation iterates all non-empty tables in the query cache to find the total number of entities.
query | The query. |
void ecs_query_fini | ( | ecs_query_t * | query | ) |
Destroy a query.
This operation destroys a query and its resources. If the query is used as the parent of subqueries, those subqueries will be orphaned and must be deinitialized as well.
query | The query. |
void * ecs_query_get_binding_ctx | ( | const ecs_query_t * | query | ) |
Get query binding ctx.
Return the value set in ecs_query_desc_t::binding_ctx.
query | The query. |
void * ecs_query_get_ctx | ( | const ecs_query_t * | query | ) |
Get query ctx.
Return the value set in ecs_query_desc_t::ctx.
query | The query. |
const ecs_filter_t * ecs_query_get_filter | ( | const ecs_query_t * | query | ) |
Get filter from a query.
This operation obtains a pointer to the internally constructed filter of the query and can be used to introspect the query terms.
query | The query. |
void * ecs_query_get_group_ctx | ( | const ecs_query_t * | query, |
uint64_t | group_id | ||
) |
Get context of query group.
This operation returns the context of a query group as returned by the on_group_create callback.
query | The query. |
group_id | The group for which to obtain the context. |
const ecs_query_group_info_t * ecs_query_get_group_info | ( | const ecs_query_t * | query, |
uint64_t | group_id | ||
) |
Get information about query group.
This operation returns information about a query group, including the group context returned by the on_group_create callback.
query | The query. |
group_id | The group for which to obtain the group info. |
ecs_query_t * ecs_query_init | ( | ecs_world_t * | world, |
const ecs_query_desc_t * | desc | ||
) |
Create a query.
This operation creates a query. Queries are used to iterate over entities that match a filter and are the fastest way to find and iterate over entities and their components.
Queries should be created once, and reused multiple times. While iterating a query is a cheap operation, creating and deleting a query is expensive. The reason for this is that queries are "prematched", which means that a query stores state about which entities (or rather, tables) match with the query. Building up this state happens during query creation.
Once a query is created, matching only happens when new tables are created. In most applications this is an infrequent process, since it only occurs when a new combination of components is introduced. While matching is expensive, it is importent to note that matching does not happen on a per-entity basis, but on a per-table basis. This means that the average time spent on matching per frame should rapidly approach zero over the lifetime of an application.
A query provides direct access to the component arrays. When an application creates/deletes entities or adds/removes components, these arrays can shift component values around, or may grow in size. This can cause unexpected or undefined behavior to occur if these operations are performed while iterating. To prevent this from happening an application should either not perform these operations while iterating, or use deferred operations (see ecs_defer_begin and ecs_defer_end).
Queries can be created and deleted dynamically. If a query was not deleted (using ecs_query_fini) before the world is deleted, it will be deleted automatically.
world | The world. |
desc | A structure describing the query properties. |
ecs_iter_t ecs_query_iter | ( | const ecs_world_t * | world, |
ecs_query_t * | query | ||
) |
Return a query iterator.
A query iterator lets an application iterate over entities that match the specified query. If a sorting function is specified, the query will check whether a resort is required upon creating the iterator.
Creating a query iterator is a cheap operation that does not allocate any resources. An application does not need to deinitialize or free a query iterator before it goes out of scope.
To iterate the iterator, an application should use ecs_query_next to progress the iterator and test if it has data.
Query iteration requires an outer and an inner loop. The outer loop uses ecs_query_next to test if new tables are available. The inner loop iterates the entities in the table, and is usually a for loop that uses iter.count to loop through the entities and component arrays.
The two loops are necessary because of how data is stored internally. Entities are grouped by the components they have, in tables. A single query can (and often does) match with multiple tables. Because each table has its own set of arrays, an application has to reobtain pointers to those arrays for each matching table.
world | The world or stage, when iterating in readonly mode. |
query | The query to iterate. |
bool ecs_query_next | ( | ecs_iter_t * | iter | ) |
Progress the query iterator.
This operation progresses the query iterator to the next table. The iterator must have been initialized with ecs_query_iter
. This operation must be invoked at least once before interpreting the contents of the iterator.
iter | The iterator. |
bool ecs_query_next_instanced | ( | ecs_iter_t * | iter | ) |
Same as ecs_query_next, but always instanced.
See "instanced" property of ecs_filter_desc_t.
iter | The iterator. |
bool ecs_query_next_table | ( | ecs_iter_t * | iter | ) |
Fast alternative to ecs_query_next that only returns matched tables.
This operation only populates the ecs_iter_t::table field. To access the matched components, call ecs_query_populate.
If this operation is used with a query that has inout/out terms, those terms will not be marked dirty unless ecs_query_populate is called.
iter | The iterator. |
bool ecs_query_orphaned | ( | const ecs_query_t * | query | ) |
Returns whether query is orphaned.
When the parent query of a subquery is deleted, it is left in an orphaned state. The only valid operation on an orphaned query is deleting it. Only subqueries can be orphaned.
query | The query. |
int ecs_query_populate | ( | ecs_iter_t * | iter, |
bool | when_changed | ||
) |
Populate iterator fields.
This operation can be combined with ecs_query_next_table to populate the iterator fields for the current table.
Populating fields conditionally can save time when a query uses change detection, and only needs iterator data when the table has changed. When this operation is called, inout/out terms will be marked dirty.
In cases where inout/out terms are conditionally written and no changes were made after calling ecs_query_populate, the ecs_query_skip function can be called to prevent the matched table components from being marked dirty.
This operation does should not be used with queries that match disabled components, union relationships, or with queries that use order_by.
When the when_changed argument is set to true, the iterator data will only populate when the data has changed, using query change detection.
iter | The iterator. |
when_changed | Only populate data when result has changed. |
void ecs_query_set_group | ( | ecs_iter_t * | it, |
uint64_t | group_id | ||
) |
Set group to iterate for query iterator.
This operation limits the results returned by the query to only the selected group id. The query must have a group_by function, and the iterator must be a query iterator.
Groups are sets of tables that are stored together in the query cache based on a group id, which is calculated per table by the group_by function. To iterate a group, an iterator only needs to know the first and last cache node for that group, which can both be found in a fast O(1) operation.
As a result, group iteration is one of the most efficient mechanisms to filter out large numbers of entities, even if those entities are distributed across many tables. This makes it a good fit for things like dividing up a world into cells, and only iterating cells close to a player.
The group to iterate must be set before the first call to ecs_query_next. No operations that can add/remove components should be invoked between calling ecs_query_set_group and ecs_query_next.
it | The query iterator. |
group_id | The group to iterate. |
void ecs_query_skip | ( | ecs_iter_t * | it | ) |
Skip a table while iterating.
This operation lets the query iterator know that a table was skipped while iterating. A skipped table will not reset its changed state, and the query will not update the dirty flags of the table for its out columns.
Only valid iterators must be provided (next has to be called at least once & return true) and the iterator must be a query iterator.
it | The iterator result to skip. |
char * ecs_query_str | ( | const ecs_query_t * | query | ) |
Convert query to string.
query | The query. |
int32_t ecs_query_table_count | ( | const ecs_query_t * | query | ) |
Returns number of tables query matched with.
query | The query. |