From 1effcec37c43bfc45f0a89fb16cc7eaf1c7dbbfe Mon Sep 17 00:00:00 2001 From: Ukendio Date: Wed, 31 Jul 2024 03:46:49 +0200 Subject: [PATCH] Add queries page --- docs/.vitepress/config.mts | 2 +- docs/learn/concepts/builtin-components.md | 3 - docs/learn/concepts/queries.md | 101 ++++++++++++++++++++++ docs/learn/concepts/relationships.md | 24 +---- 4 files changed, 105 insertions(+), 25 deletions(-) delete mode 100644 docs/learn/concepts/builtin-components.md create mode 100644 docs/learn/concepts/queries.md diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index f792b154..60b0e3c9 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -36,7 +36,7 @@ export default defineConfig({ text: 'Concepts', items: [ { text: 'Entities and Components', link: 'learn/concepts/entities-and-components' }, - { text: 'Builtin Components', link: 'learn/concepts/builtin-components' }, + { text: 'Queries', link: 'learn/concepts/queries' }, { text: 'Relationships', link: 'learn/concepts/relationships' }, ] }, diff --git a/docs/learn/concepts/builtin-components.md b/docs/learn/concepts/builtin-components.md deleted file mode 100644 index 1346d9f7..00000000 --- a/docs/learn/concepts/builtin-components.md +++ /dev/null @@ -1,3 +0,0 @@ -## TODO - -This is a TODO stub. \ No newline at end of file diff --git a/docs/learn/concepts/queries.md b/docs/learn/concepts/queries.md new file mode 100644 index 00000000..70e8823f --- /dev/null +++ b/docs/learn/concepts/queries.md @@ -0,0 +1,101 @@ +# Queries + +## Introductiuon + +Queries enable games to quickly find entities that satifies provided conditions. + +Jecs queries can do anything from returning entities that match a simple list of components, to matching against entity graphs. + +This manual contains a full overview of the query features available in Jecs. Some of the features of Jecs queries are: + +- Queries have support for relationships pairs which allow for matching against entity graphs without having to build complex data structures for it. +- Queries support filters such as `query:with(...)` if entities are required to have the components but you don’t actually care about components value. And `query:without(...)` which selects entities without the components. +- Queries can be drained or reset on when called, which lets you choose iterator behaviour. +- Queries can be called with any ID, including entities created dynamically, this is useful for pairs. +- Queries are already fast but can be futher inlined via `query:archetypes()` for maximum performance to eliminate function call overhead which is roughly 70-80% of the cost for iteration. + +## Creating Queries +This section explains how to create queries in the different language bindings. + +:::code-group +```luau [luau] +for _ in world:query(Position, Velocity) do end +``` +```typescript [typescript] +for (const [_] of world.query(Position, Velocity)) {} +``` + +### Components +A component is any single ID that can be added to an entity. This includes tags and regular entities, which are IDs that do not have the builtin `Component` component. To match a query, an entity must have all the requested components. An example: + +```luau +local e1 = world:entity() +world:add(e1, Position) + +local e2 = world:entity() +world:add(e2, Position) +world:add(e2, Velocity) + +local e3 = world:entity() +world:add(e3, Position) +world:add(e3, Velocity) +world:add(e3, Mass) + +``` +Only entities `e2` and `e3` match the query Position, Velocity. + +### Wildcards + +Jecs currently only supports the `Any` type of wildcards which a single result for the first component that it matches. + +When using the `Any` type wildcard it is undefined which component will be matched, as this can be influenced by other parts of the query. It is guaranteed that iterating the same query twice on the same dataset will produce the same result. + +Wildcards are particularly useful when used in combination with pairs (next section). + +### Pairs + +A pair is an ID that encodes two elements. Pairs, like components, can be added to entities and are the foundation for [Relationships](relationships.md). + +The elements of a pair are allowed to be wildcards. When a query pair returns an `Any` type wildcard, the query returns at most a single matching pair on an entity. + +The following sections describe how to create queries for pairs in the different language bindings. + +:::code-group +```luau [luau] +local Likes = world:entity() +local bob = world:entity() +for _ in world:query(pair(Likes, bob)) do end +``` +```typescript [typescript] +const Likes = world.entity() +const bob = world.entity() +for (const [_] of world.query(pair(Likes, bob))) {} +``` + +When a query pair contains a wildcard, the `world:target()` function can be used to determine the target of the pair element that matched the query: + +:::code-group +```luau [luau] +for id in world:query(pair(Likes, jecs.Wildcard)) do + print(`entity {getName(id)} likes {getName(world, world:target(id, Likes))}`) +end +``` +```typescript [typescript] +const Likes = world.entity() +const bob = world.entity() +for (const [_] of world.query(pair(Likes, jecs.Wildcard))) { + print(`entity ${getName(id)} likes ${getName(world.target(id, Likes))}`) +} +``` + +### Filters +Filters are extensions to queries which allow you to select entities from a more complex pattern but you don't actually care about the component values. + +The following filters are supported by queries: + +Identifier | Description +---------- | ----------- +With | Must match with all terms. +Without | Must not match with provided terms. + +This page takes wording and terminology directly from Flecs [documentation](https://www.flecs.dev/flecs/md_docs_2Queries.html) diff --git a/docs/learn/concepts/relationships.md b/docs/learn/concepts/relationships.md index 76028961..2ac8a89f 100644 --- a/docs/learn/concepts/relationships.md +++ b/docs/learn/concepts/relationships.md @@ -159,25 +159,7 @@ world.add(e, jecs.ChildOf, Position) ## Relationship wildcards -When querying for relationship pairs, it is often useful to be able to find all instances for a given relationship or target. To accomplish this, an application can use wildcard expressions. Consider the following example, that queries for all entities with a `Likes` relationship: - -:::code-group -```luau [luau] -for id in world:query(pair(Likes, jecs.Wildcard)) do - local rel = get_name(ecs_pair_relation(world.entityIndex, id)) - local obj = get_name(ecs_pair_object(world.entityIndex, id)) - print(`entity {id} has relationship {rel} {obj}`) -end - -``` -```typescript [typescript] -for (const [id] of world.query(pair(Likes, jecs.Wildcard))) { - const rel = get_name(ecs_pair_relation(world.entityIndex, id)) - const obj = get_name(ecs_pair_object(world.entityIndex, id)) - print(`entity ${id} has relationship ${rel} ${obj}`) -} -``` -::: +When querying for relationship pairs, it is often useful to be able to find all instances for a given relationship or target. To accomplish this, an game can use wildcard expressions. Wildcards may used for the relationship or target part of a pair @@ -209,7 +191,7 @@ Because of the way pair IDs are encoded, a pair will never be in the low id rang Fragmentation is a property of archetype-based ECS implementations where entities are spread out over more archetypes as the number of different component combinations increases. The overhead of fragmentation is visible in two areas: - Archetype creation - ueries (queries have to match & iterate more archetypes) -Applications that make extensive use of relationships might observe high levels of fragmentation, as relationships can introduce many different combinations of components. While the Flecs storage is optimized for supporting large amounts (hundreds of thousands) of archetypes, fragmentation is a factor to consider when using relationships. +Games that make extensive use of relationships might observe high levels of fragmentation, as relationships can introduce many different combinations of components. While the Jecs storage is optimized for supporting large amounts (hundreds of thousands) of archetypes, fragmentation is a factor to consider when using relationships. Union relationships are planned along with other improvements to decrease the overhead of fragmentation introduced by relationships. @@ -217,7 +199,7 @@ Union relationships are planned along with other improvements to decrease the ov When an ID added to an entity is deleted, all references to that ID are deleted from the storage. For example, when the component Position is deleted it is removed from all entities, and all archetypes with the Position component are deleted. While not unique to relationships, it is more common for relationships to trigger cleanup actions, as relationship pairs contain regular entities. -The opposite is also true. Because relationship pairs can contain regular entities which can be created on the fly, archetype creation is more common than in applications that do not use relationships. While Jecs is optimized for fast archetypes creation, creating and cleaning up archetypes is inherently more expensive than creating/deleting an entity. Therefore archetypes creation is a factor to consider, especially for games that make extensive use of relationships. +The opposite is also true. Because relationship pairs can contain regular entities which can be created on the fly, archetype creation is more common than in games that do not use relationships. While Jecs is optimized for fast archetypes creation, creating and cleaning up archetypes is inherently more expensive than creating/deleting an entity. Therefore archetypes creation is a factor to consider, especially for games that make extensive use of relationships. ### Indexing