All skills

Structure a Bevy app around its Entity Component System: build the App with plugins, define Component/Resource types, write systems with Query/Res/Commands, filter and order systems, and use the Time resource for frame-rate-independent motion. Use when building or debugging a Bevy game in Rust — when the user mentions Bevy, ECS, App::new, add_systems, Query, Commands, components/systems, or a Cargo.toml depending on bevy.

Use this Skill: https://skilld.dev/gh/gamedev-skills/awesome-gamedev-agent-skills/bevy-ecs

This session only. Nothing lands on disk.

referencesqueries-and-scheduling.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Bevy queries & scheduling detail (0.19)

Depth behind the ECS skill: query filters and access, schedules and ordering, states, change detection, and the Commands lifecycle. Verify any borderline API against the docs for your pinned Bevy version — minor releases move things.

Query anatomy

A Query<D, F> has a data part D (what you read/write) and an optional filter part F (which entities, without fetching their data).

// Data: read Name, write Transform. Filter: must have Player, must NOT have Frozen.
Query<(&Name, &mut Transform), (With<Player>, Without<Frozen>)>

Common filters:

  • With<T> / Without<T> — entity has / lacks a component (no data fetched).
  • Added<T> — T was added since this system last ran.
  • Changed<T> — T was added or mutably accessed since last run (change detection).
  • Or<(...)> — combine filters disjunctively.

Optional and entity access in the data part:

Query<(Entity, &Transform, Option<&Velocity>)>  // Entity id; Velocity may be absent

Single-entity access

For a query you expect to match exactly one entity (e.g. the player), single() and single_mut() return a Result in 0.16+ (they replaced the older get_single/panicking single):

fn read_player(q: Query<&Transform, With<Player>>) {
    if let Ok(transform) = q.single() {
        // exactly one Player matched
    }
}

Iterating with for x in &query is always valid and the safest default.

Avoiding conflicting access

Two systems can run in parallel only if their data accesses don't conflict. Two queries within one system that both mutably touch the same component will panic at startup. Fixes:

  1. Disjoint with filters — With<Player> vs Without<Player> guarantees the sets never overlap, so both can be &mut.
  2. ParamSet — when sets can overlap, access them one at a time:
fn swap(mut set: ParamSet<(
    Query<&mut Transform, With<A>>,
    Query<&mut Transform, With<B>>,
)>) {
    for mut t in &mut set.p0() { /* ... */ }
    for mut t in &mut set.p1() { /* ... */ }
}

Schedules and ordering

Built-in schedules you'll use most:

  • Startup — once, before the first Update.
  • Update — every frame.
  • FixedUpdate — fixed timestep; use it for physics/gameplay that needs determinism (read time.delta_secs() here too; it's the fixed step).
  • PreUpdate / PostUpdate — around Update for setup/teardown ordering.

Ordering within a schedule:

// Explicit pairwise order.
app.add_systems(Update, (input, movement, collision).chain());

// Named constraints.
app.add_systems(Update, movement.before(collision));
app.add_systems(Update, camera_follow.after(movement));

System sets

Group systems into a SystemSet to order whole phases and attach shared run conditions:

#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
enum GameSet { Input, Logic, Render }

app.configure_sets(Update, (GameSet::Input, GameSet::Logic, GameSet::Render).chain());
app.add_systems(Update, read_input.in_set(GameSet::Input));
app.add_systems(Update, (move_units, resolve).in_set(GameSet::Logic));

Run conditions

app.add_systems(Update, pause_menu.run_if(in_state(AppState::Paused)));
app.add_systems(Update, autosave.run_if(on_timer(Duration::from_secs(30))));

States

States model app-wide modes (menu, playing, paused). Use OnEnter/OnExit schedules for transition logic and in_state to gate Update systems.

#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
enum AppState { #[default] Menu, Playing }

app.init_state::<AppState>()
   .add_systems(OnEnter(AppState::Playing), spawn_level)
   .add_systems(OnExit(AppState::Playing), cleanup_level)
   .add_systems(Update, gameplay.run_if(in_state(AppState::Playing)));

// Transition from a system:
fn start(mut next: ResMut<NextState<AppState>>) { next.set(AppState::Playing); }

Change detection

Changed<T> / Added<T> filters and the Ref<T>/Mut<T> wrappers let systems react only to modified data — cheaper than recomputing every frame. Note: writing through a &mut T marks it changed even if the value is identical; guard with a value check if that matters.

Commands lifecycle

Commands queue structural changes (spawn, despawn, insert/remove components, insert resources). They are deferred and applied at the next sync point (end of the schedule stage), so:

  • An entity spawned this frame is not in queries until a later system/stage.
  • commands.entity(e).despawn() removes the entity; in 0.16+ this also removes its children (the old explicit despawn_recursive was folded in).
fn spawn_bullet(mut commands: Commands) {
    let id = commands.spawn((Bullet, Transform::default())).id();
    commands.entity(id).insert(Velocity(Vec2::Y * 500.0));
}

For immediate, exclusive access to the whole World (one-off setup, complex queries), use an exclusive system fn(&mut World) — it can't run in parallel, so use sparingly.

Messages / observers — version caution

Bevy's buffered event API evolved into the message API in recent releases, while observers remain event-oriented. If systems need buffered communication, look up the exact message/observer API for the pinned release rather than copying an example from a different version.

Source: SKILL.md on GitHub

No alerts1mo3 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    This skill provides a comprehensive guide for structuring Rust applications using the Bevy game engine's Entity Component System (ECS). No security risks were identified.

  • Socket1mo

    No alerts

  • Snyk1mo

    Risk: LOW · No issues

Signed by skilld at 3727d02. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 2 months ago

README badge

README badge for gamedev-skills/awesome-gamedev-agent-skills/bevy-ecs