Skip to main content

Queries

A query visits every entity that has a set of components. Build one from a tuple of terms:

var query = world.query(.{ *Position, *const Velocity });
while (query.next()) |view| {
view.get(*Position).x += view.get(*const Velocity).dx;
}

view.entity is the current entity, and view.get(*T) or view.get(*const T) returns a pointer to one of its components.

Terms​

TermMatches entities that...Access
*Thave a Tread and write
*const Thave a Tread only
clutch.With(T)have a Tnone
clutch.Without(T)don't have a Tnone
clutch.Added(T)were given a T this ticknone
clutch.Changed(T)had their T changed this ticknone
clutch.Removed(T)lost their T this ticknone

Every term must hold for an entity to match. The last three are covered in Change detection.

Order and changes during a query​

A query walks the packed entries of the smallest component storage that every match must have. That's why a query for a rare component costs almost nothing, even in a huge world. The order of the visits is unspecified, so don't rely on it.

You may despawn the current entity, or add and remove its components, while a query runs. The query still visits every other entity exactly once. Pointers you got from view.get stop being valid once that component's storage changes, so take them again after a change instead of keeping them.

Queries in systems​

A system takes a query as a parameter, and the world builds it before the system runs:

fn move(query: clutch.Query(.{ *Position, *const Velocity })) !void {
var iter = query;
while (iter.next()) |view| { ... }
}

Two parameters that both write the same component, or a write and a read of it, are a compile error, so a system can't alias its own data.