Skip to content

Queries

Introduction

Queries are the main method for you to look for a group of entities based on context/shape and operate on them.

You can create a query with ecs.query(Terms...):

lua
function query<ReadTerms>(
    ...: Ent<ReadTerms> -- Type simplified for docs
): Query<...ReadTerms>

Queries are used for a lot of things, but a simple example is looking for entities which have a specific Component.

luau
local alice = ecs.entity()
local bob = ecs.entity()
ecs.set(alice, Name, "Alice")
ecs.set(bob, Name, "Bob")

for entity, name in ecs.query(Name):entities() do
    print(entity, name)
end
-- Output:
--  1026 Alice
--  1027 Bob

query:entities() can be run multiple times and the query will remain accurate. E.g.,

luau
local Tag = ecs.entity()
local e1 = ecs.entity()
local e2 = ecs.entity()
ecs.add(e1, Tag)
local q = ecs.query(Tag)
for e in q:entities() do
    print(e) -- outputs only e1
end
ecs.add(e2, Tag)
for e in q:entities() do
    print(e) -- outputs e1 and e2
end

Wildcard Queries

With Wildcard Pairs you can query for less Specific relationships. pair(relation, Wildcard) and pair(Wildcard, target) are both valid for queries.

luau
for entity in ecs.query(pair(Likes, b2.Wildcard)):entities() do
    print(`entity {entity} likes {ecs.target(entity, Likes)}`)
end

Monitors

Monitors are similar to Hooks, but with a few key differences. Monitors are query-based, so they allow you to broadly percieve structural changes. Monitors will inform you when an entity starts, or stops matching a query. Many monitors can exist for one component or query - whereas only one Hook of each kind can exist per Component. Monitors can be created or destroyed at any time - whereas hooks cannot be modified or removed once the Id is in use. In a monitor's callback, you cannot safely modify an entity's data - whereas hooks allow you to add/set/remove components as you please. You can also safely expect monitors to take a glug more frametime than hooks, because they need to run checks any time you move a query term for any entity.

You can create a new monitor with query:monitor_added(callback) or query:monitor_removed(callback).

query:monitor_added

luau
function monitor_added<Reads...>(
    self: Query<Reads...>,
    callback: (Entity, Reads...) -> ()
): () -> ()

Calls when an entity has started matching the query, as well as all of the data which a query normally reads. Returns a destructor.

query:monitor_removed

luau
function monitor_removed(
    self: Query,
    callback: (Entity) -> ()
): ()

Calls when an entity has stopped matching the query. Returns a destructor.

Query Builder Methods

These methods are intended to be called before any Matching Methods.

query:with

luau
function with<Reads...>(
    self: Query<Reads...>,
    term: Entity,
    ...: Entity
): Query<Reads...>

Ensures the query will only match entities which satisfy the provided terms.

query:without

luau
function with<Reads...>(
    self: Query<Reads...>,
    term: Entity,
    ...: Entity
): Query<Reads...>

Ensures the query will never match entities which satisfy the provided terms.

Query Matching Methods

query:entities

luau
function entities<Reads...>(
    self: Query<Reads...>,
    cached: true?
): () -> (Ent, Reads...)

Returns an iterator for each entity and the value of components.

query:monitor_added

luau
function monitor_added<Reads...>(
    self: Query<Reads...>,
    callback: (Entity, Reads...) -> ()
): () -> ()

Calls when an entity has started matching the query, as well as all of the data which a query normally reads. Returns a destructor.

query:monitor_removed

luau
function monitor_removed(
    self: Query,
    callback: (Entity) -> ()
): ()

Calls when an entity has stopped matching the query. Returns a destructor.

query:archetypes

luau
function archetypes(
    self: Query,
): { Arch }

Returns all archetypes that match a query. See What is an Archetype?

query:match

luau
function match(
    self: Query,
    archetype: Arch,
): boolean

Returns whether or not an archetype matches a given query.

query:archetypes_cached

luau
function archetypes_cached(
    self: Query
): { Arch }

Returns a READONLY list of archetypes which match the query with caching

query:observe_added

luau
function observe_added(
    self: Query,
    callback: (Arch) -> ()
): () -> ()

Calls when an archetype is created which matches the query. Returns a destructor.

query:observe_removed

luau
function observe_removed(
    self: Query,
    callback: (Arch) -> ()
): () -> ()

Calls when an archetype which matches the query is deleted. Returns a destructor.

query:monitor_added_row

luau
function monitor_added_row(
    self: Query,
    callback: (Ent, Arch, number) -> ()
): () -> ()

Calls when an entity starts matching a query without reading any data.

query:monitor_removed_row

luau
function monitor_removed_row(
    self: Query,
    callback: (Ent, Arch, number) -> ()
): () -> ()

Calls when an entity stops matching a query without reading any data.