Queries & Iteration¶
Queries let you find and iterate over entities by their tags, components, or set membership.
ForEachEntity¶
The most common way to iterate entities is with [ForEachEntity] on a system method. It supports the same filtering criteria as the query builder:
// By tag
[ForEachEntity(Tag = typeof(GameTags.Player))]
void Execute(ref Position position, in Velocity velocity) { ... }
// By multiple tags
[ForEachEntity(Tags = new[] { typeof(BallTags.Ball), typeof(BallTags.Active) })]
void Execute(in ActiveBall ball) { ... }
// By components (matches any entity that has these components, regardless of tags)
[ForEachEntity(MatchByComponents = true)]
void Execute(ref Position position, in Velocity velocity) { ... }
// By set membership
[ForEachEntity(Set = typeof(SampleSets.HighlightedParticle))]
void Execute(in ParticleView particle) { ... }
See Systems for full details.
QueryBuilder¶
For manual iteration outside of [ForEachEntity], use the query builder via WorldAccessor.Query():
Filtering by Tags¶
// Include entities with specific tags
query.WithTags<GameTags.Player>()
query.WithTags<GameTags.Player, GameTags.Active>()
// Exclude entities with specific tags
query.WithoutTags<GameTags.Dead>()
Filtering by Components¶
// Include entities that have specific components
query.WithComponents<Position, Velocity>()
// Exclude entities that have specific components
query.WithoutComponents<Frozen>()
Filtering by both Components and Tags¶
Tag and component filters can be combined. This is useful when a tag is shared across multiple entity types that have different component layouts, and you only want to iterate entities that have specific components:
// Only iterate Renderable entities that also have a Velocity component
var query = World.Query()
.WithTags<CommonTags.Renderable>()
.WithComponents<Velocity>();
For example, if both FishEntity and ObstacleEntity share a Renderable tag but only FishEntity has a Velocity component, this query will skip obstacles and only visit fish.
Iteration Patterns¶
EntityIndices — Iterate Entity by Entity¶
foreach (EntityIndex entityIndex in World.Query().WithTags<GameTags.Player>().EntityIndices())
{
ref Position pos = ref World.Component<Position>(entityIndex).Write;
pos.Value.y += 1f;
}
Aspect Queries¶
Aspects provide a generated Query() method for manual iteration with bundled component access:
partial struct PlayerView : IAspect, IRead<Position>, IWrite<Health> { }
foreach (var player in PlayerView.Query(World).WithTags<GameTags.Player>())
{
float3 pos = player.Position;
player.Health -= 1f;
}
Note
Aspect queries do not automatically filter by the aspect's components — you must provide filtering criteria. Either scope with WithTags or call MatchByComponents() to filter to only groups that have all the aspect's components:
See Aspects for details on defining aspects.
Filtering by Set¶
Calling InSet<T>() filters iteration to only entities that are members of the set:
partial struct ParticleView : IAspect, IRead<Position>, IWrite<ColorComponent> { }
foreach (var particle in ParticleView.Query(World).InSet<HighlightedParticles>())
{
particle.Color = Color.yellow;
}
GroupSlices — Low-Level Bulk Access¶
For advanced performance-critical scenarios, you can iterate per-group and access component buffers directly. See Groups & TagSets — GroupSlices for details.
Counting¶
int total = World.CountAllEntities();
int players = World.CountEntitiesWithTags<GameTags.Player>();
int inGroup = World.CountEntitiesInGroup(group);
int matched = World.Query().WithTags<GameTags.Enemy>().Count();
Single Entity Access¶
For queries that should match exactly one entity:
// Assert exactly one match
EntityAccessor player = World.Query().WithTags<GameTags.Player>().Single();
ref Health hp = ref player.Get<Health>().Write;
// Try-pattern (returns false if 0 or 2+ matches)
if (World.Query().WithTags<GameTags.Player>().TrySingle(out var player))
{
ref readonly Position pos = ref player.Get<Position>().Read;
}