| Safe Haskell | None |
|---|---|
| Language | GHC2024 |
Mischief.ECS.Tutorial.Guides.QueryBasics
Description
Synopsis
Learn You an ECS for Great Mischief! - 2.3. Query Basics
In an ECS, queries are a mechanism used to read data based on a certain user-defined format. In Mischief, they're a bit more complex than that; queries are pure functions chained together which can trigger effects in the World, as well as retrieve data.
This chapter is an introduction to the q quasi-quoter, and a short how-to guide on reading data from entities. The next chapters
delve into more complex queries.
Query Data
Query Data is a tuple of types that are queryable. Query Data can be written using the qd macro. Here are the things you can query for:
- Components: get a component's value.
[qd|Name, Health|]
- Relationships: get relationships with a specific component. Either all relationships, or just with a specific entity. This will return either a
single
Relor a list of them.
[qd|Likes -> *|]
[qd|Likes -> bob|]
- Transitive Components: similar to the previous but you give it an entire query to grab from each of the targets. Will return a
Fromor a list of them.
[qd|Likes -> (Name, Health)|]
- Resource: Grabs a resource from the world.
[qd|Res SomeRes]
When you query for each of these types, the query will filter out any entities that don't have them.
For instance, if you're querying for Health, you're leaving out entities that don't have Health, and if
you're querying for Likes -> * you're leaving out entities that like no one.
In order to include optional components, resources, relationships, you can use the Maybe keyword:
[qd|Name, Maybe Health, Maybe Likes -> (Name)]
Query Filters
Query Filters can be used to filter the entities that a query is looking at. They can be written with the qf quasi-quoter.
There are three such filters:
- With: filters out entities that do not have this component.
[qf|With Player|]
- Without: filters out entities that have this component.
[qf|Without Enemy|]
- Changed: filters out most entities that haven't had this component be re-inserted since the current system last ran:
[qf|Changed Name|]
Filters can be combined with && and ||. Separating them by , will result in an implicit &&:
[qf|With Health, Changed Name|]
Is the same as:
[qf|With Health && Changed Name|]
What about q?
q combines the previous two quasi-quoters, and produces a Query.
For instance, the following will result in a Query (Name, Player):
[q|Name, Player / Without Enemy|]
The first part (left of the /) is the same as qd, while the other is the same as qf. The / along with the filter can be omitted. Note that
the filter in q must be an Archetype Filter!
Additionally, q accepts an Entity at the start, filling the Query with just the components from that Entity:
[q|bob. Name, Health|]
Grabbing the Name and Health of just bob is an O(1) operation.
What was that about a Query?
Query (Name, Player) is a Query through which the Name and Player components flow. You can think of it
as a wrapper around [(Name, Player)], although it's a bit more complicated than that.
The list of components can be extracted from a Query using query or single:
names <-query[q|Name|]
JustbobName <-single[q|bob. Name|]
single is the same as query but instead of returning a list, it returns a Maybe depending on if that list had exactly one element or not. It is useful
if you're retrieving the components of a specific entity or if you know there's only one entity that could fit your query (for instance, there is only one Player spawned).