A new querying mechanism that is simpler to use, simpler to explain and document, and solves some of the issues of the purely predicate-based core API I've added for 2.0.
The goal is to keep the user-facing API largely the same conceptually (but a breaking change is fine), based off on Miniplex 2.0 Beta's current API:
But instead of creating a set of nested archetypes (one bucket derived from world, the other derived from the first bucket), and an ad-hoc iterator that implements the low health condition (a functionality I've just removed from the library anyway), this will now always create (or re-use) a single instance of a new query bucket class.
Instances of these classes have knowledge of what archetypes they represent, which paves the way for some optimizations. For example, in the current version of Miniplex 2.0 beta, the following three statements, even though semantically representing exactly the same query, will create a total of 5 buckets:
In a query object approach, we could do the kind of optimizations that detect that these actually represent the same query semantically, and then return memoized query buckets instead of creating new ones.
Suggested API
We want to simplify things, so instead of going crazy with nested buckets, let's reduce the whole setup to a builder-based approach, where the user
Constructs a query
Passes that query to world.query()
Query is a class that can be instantiated and exposes a query builder that consolidates added statements into its existing query state. The user may create such an object directly:
The world.query function returns a QueryBucket instance that receives entities based on the given query. It, too, exposes a query function to allow further nesting, but unlike the currently released beta, it will no longer nest buckets, it will simply create a new query based off of the state of the bucket's original query. Example:
Here, deadEnemies contains entities that have both the enemy and dead components, but the actual bucket sources its data directly from the world, instead of being nested under the enemies bucket. This means that if we at some other part of the project do this:
A new querying mechanism that is simpler to use, simpler to explain and document, and solves some of the issues of the purely predicate-based core API I've added for 2.0.
The goal is to keep the user-facing API largely the same conceptually (but a breaking change is fine), based off on Miniplex 2.0 Beta's current API:
But instead of creating a set of nested archetypes (one bucket derived from
world
, the other derived from the first bucket), and an ad-hoc iterator that implements the low health condition (a functionality I've just removed from the library anyway), this will now always create (or re-use) a single instance of a new query bucket class.Instances of these classes have knowledge of what archetypes they represent, which paves the way for some optimizations. For example, in the current version of Miniplex 2.0 beta, the following three statements, even though semantically representing exactly the same query, will create a total of 5 buckets:
In a query object approach, we could do the kind of optimizations that detect that these actually represent the same query semantically, and then return memoized query buckets instead of creating new ones.
Suggested API
We want to simplify things, so instead of going crazy with nested buckets, let's reduce the whole setup to a builder-based approach, where the user
world.query()
Query
is a class that can be instantiated and exposes a query builder that consolidates added statements into its existing query state. The user may create such an object directly:But we can also accept a function that receives a new
Query
instance and returns aQuery
instance to make the API nicer:The
world.query
function returns aQueryBucket
instance that receives entities based on the given query. It, too, exposes aquery
function to allow further nesting, but unlike the currently released beta, it will no longer nest buckets, it will simply create a new query based off of the state of the bucket's original query. Example:Here,
deadEnemies
contains entities that have both theenemy
anddead
components, but the actual bucket sources its data directly from the world, instead of being nested under theenemies
bucket. This means that if we at some other part of the project do this:...
deadEnemies
anddeadEnemies2
will contain exactly the same bucket object.