bevy-ecs-queries
Skill29 starsChanged 11 days agoMITView on GitHub
Use when writing `Query<D, F>` with `With`/`Without`/`Or`, detecting changes with `Changed<T>`/`Added<T>`, parallelising with `par_iter_mut`, looking up entity lists with `iter_many(..).matched()`, building a lens with `transmute_lens`, filtering resource entities with `Without<IsResource>`, or fixing generic-query errors naming `IterQueryData` or `SingleEntityQueryData` in Bevy 0.20.
In this repository34 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- bevy-a11ySkill
- bevy-animationSkill
- bevy-assetsSkill
- bevy-audioSkill
- bevy-camerasSkill
- bevy-captureSkill
- bevy-cargo-featuresSkill
- bevy-core-conceptsSkill
- bevy-custom-assetsSkill
- bevy-diagnostics-profilingSkill
- bevy-ecs-componentsSkill
- bevy-ecs-systemsSkill
- bevy-fluentSkill
- bevy-input-actionsSkill
- bevy-migration-0-17-to-0-18Skill
- bevy-migration-0-18-to-0-19Skill
- bevy-migration-0-19-to-0-20Skill
- bevy-pbr-materialsSkill
- bevy-physicsSkill
- bevy-portingSkill
- bevy-renderingSkill
- bevy-save-loadSkill
- bevySkill
- bevy-testingSkill
- bevy-uiSkill
- bevy-vfxSkill
- bevy-voxel-dataSkill
- bevy-voxel-pipelineSkill
- bevy-voxel-runtimeSkill
- bevy-wasm-webgpuSkill
- similarity-rsSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 139
All built-in query types satisfy all three.
- Very specific: line 146
DeferredWorld::queryis deprecated (0.20): Call query_state.query_mut(&mut deferred_world).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Bevy 0.20 — ECS Queries
When to use this skill
- Reading or writing components from a system.
- Filtering by presence (
With/Without), alternation (Or), or change detection (Changed/Added). - Parallelising over a large entity set with
par_iter_mut. - Iterating a list of entities with
iter_many/iter_many_mut(yieldResultsince 0.20). - Borrowing a subset of a query via a lens (
transmute_lens). - Compiler error mentioning
IterQueryData,SingleEntityQueryDataorArchetypeQueryData. - A broad query (
Query<Entity>,Query<EntityRef>) conflicting withResMutsince 0.19.
Canonical pattern
use bevy::ecs::resource::IsResource;
use bevy::prelude::*;
#[derive(Component, Default)]
struct Health(f32);
#[derive(Component, Default)]
struct Velocity(Vec3);
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Enemy;
#[derive(Resource, Default)]
struct Targets(Vec<Entity>);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_resource::<Targets>()
.add_systems(
Update,
(
move_things,
on_health_changed,
damage_visible_enemies,
integrate_in_parallel,
heal_targets,
count_world_entities,
),
)
.run();
}
// Sequential iteration. `&` for read, `&mut` for write.
fn move_things(time: Res<Time>, mut q: Query<(&Velocity, &mut Transform)>) {
let dt = time.delta_secs();
for (vel, mut tf) in &mut q {
tf.translation += vel.0 * dt;
}
}
// Change detection. `Changed<T>` fires on insert OR mutation; `Added<T>` only on insert.
fn on_health_changed(q: Query<(Entity, &Health), Changed<Health>>) {
for (entity, hp) in &q {
info!("entity {:?} now has {} hp", entity, hp.0);
}
}
// Combined filters. `Or<(...)>` alternates over filters, not components.
fn damage_visible_enemies(
mut q: Query<&mut Health, (With<Enemy>, Without<Player>, Or<(Added<Enemy>, Changed<Transform>)>)>,
) {
for mut hp in &mut q {
hp.0 -= 1.0;
}
}
// Parallel iteration. No `Commands` inside the closure.
fn integrate_in_parallel(mut q: Query<(&Velocity, &mut Transform)>) {
q.par_iter_mut().for_each(|(vel, mut tf)| {
tf.translation += vel.0 * 0.016;
});
}
// Many-entity lookup. 0.20: `iter_many*` yield `Result`; `.matched()` skips misses.
fn heal_targets(targets: Res<Targets>, mut q: Query<&mut Health>) {
let mut iter = q.iter_many_mut(targets.0.iter()).matched();
while let Some(mut hp) = iter.fetch_next() {
hp.0 += 1.0;
}
}
// Broad queries (`Entity`, `EntityRef`, `Option<&T>`) also match resource
// entities since 0.19. `Without<IsResource>` avoids conflicts with `ResMut`.
fn count_world_entities(q: Query<EntityRef, Without<IsResource>>, mut targets: ResMut<Targets>) {
targets.0.clear();
let _ = q.iter().count();
}
// Query lens: narrow a query for a helper without a new system param.
fn use_lens(mut q: Query<(&mut Transform, &Velocity)>) {
let mut lens = q.transmute_lens::<&Transform>();
let _read_only: Query<&Transform> = lens.query();
}Generic query bounds (0.19+)
use bevy::ecs::query::{IterQueryData, QueryData};
// Iterating generic query data needs `IterQueryData`.
fn generic_iter<D: IterQueryData>(mut query: Query<D>) {
for _item in &mut query {}
}
// Any `QueryData` can still be walked with the lending `fetch_next`.
fn generic_fetch<D: QueryData>(mut query: Query<D>) {
let mut iter = query.iter_mut();
while let Some(_item) = iter.fetch_next() {}
}| Bound | Required by |
IterQueryData | into_iter, iter_mut as Iterator, par_iter_mut, single_mut, get_many_mut, iter_combinations_mut, Single<D>. |
SingleEntityQueryData | transmute/transmute_lens, join, QueryIter::sort*, EntityRef::get_components, Traversal. |
ArchetypeQueryData | Query data whose per-archetype item count is known statically. Dynamic data (FilteredEntityRef/Mut) does not satisfy it. |
All built-in query types satisfy all three. Only manual QueryData impls and generic helpers need to name them.
Gotchas (0.18 → 0.20)
iter_many,iter_many_mut,iter_many_unique*andpar_iter_many*yieldResult<Item, QueryEntityError>(0.20). Stale codefor hp in q.iter_many(list)fails to compile. Add.matched()to keep the old skip-misses behaviour, or handle theErr(entity despawned or not matching the filter).QueryManyIter::sort*has no.matched(): use.flat_map(Result::ok). Inpar_iter_many(..).for_each(|item| ..)dolet Ok(item) = item else { return };.- Resources are entities (0.19).
Query<Entity>,Query<EntityRef>,Query<EntityMut>,Query<Option<&T>>andQuery<()>match the hidden resource entities. They conflict withResMut<R>/NonSendMut; addWithout<IsResource>orWithout<R>. Counting "all entities" with a broad query overcounts by the number of resources. FilteredResources*are deprecated (0.20). Build the system withQueryParamBuilder::new(|b| { b.data::<Ref<ResA>>().with::<IsResource>(); })and takeQuery<FilteredEntityRef>(orSingle<FilteredEntityRef>). UseResourceEntitiesto find a resource's entity when the query holds several.DeferredWorld::queryis deprecated (0.20). Callquery_state.query_mut(&mut deferred_world);QueryState::query_muttakesimpl Into<DeferredWorld>.- Manual
WorldQueryimpls must writeinit_nested_accessandupdate_archetypes(0.20). The default bodies were removed; empty bodies keep old behaviour for single-entity queries. EntityMut::get_components_mut::<(&mut A, &mut B)>()takes two&mutout of one entity safely; it needsSingleEntityQueryData.Query::get/get_mutreturnsResult<_, QueryEntityError>, notOption. Keep the error if you need to know why the lookup missed.Or<(With<A>, With<B>)>—Ortakes filters.Or<(A, B)>does not compile.Changed/Addedare tick-based. A system that runs every other frame misses changes from the skipped frame. Use observers or a message if you cannot miss one.#[component(summary_tick)](0.20) makesChanged<T>cheap on rarely-mutated columns.Ref<T>isClone + Copy(0.19).- Don't pair
par_iter_mutwithCommands. Spawn/despawn from a sequential system that drains a queue written by the parallel one.
See also
bevy-ecs-components— declaring the components queried here; lifecycle observers.bevy-ecs-systems— query is one of manySystemParams; run conditions.bevy-migration-0-18-to-0-19—IterQueryDatabounds, broad queries versus resources.bevy-migration-0-19-to-0-20—Resultfrom many-iterators,FilteredResourcesdeprecation.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

