bevy-ecs-expert
Master Bevy's Entity Component System (ECS) in Rust, covering Systems, Queries, Resources, and parallel scheduling.
- risk
- safe
- source
- community
- date added
- 2026-02-27
Bevy ECS Expert
Overview
A guide to building high-performance game logic using Bevy's data-oriented ECS architecture. Learn how to structure systems, optimize queries, manage resources, and leverage parallel execution.
When to Use This Skill
- Use when developing games with the Bevy engine in Rust.
- Use when designing game systems that need to run in parallel.
- Use when optimizing game performance by minimizing cache misses.
- Use when refactoring object-oriented logic into data-oriented ECS patterns.
Step-by-Step Guide
1. Defining Components
Use simple structs for data. Derive Component and Reflect.
#[derive(Component, Reflect, Default)] #[reflect(Component)] struct Velocity { x: f32, y: f32, } #[derive(Component)] struct Player;
2. Writing Systems
Systems are regular Rust functions that query components.
fn movement_system( time: Res<Time>, mut query: Query<(&mut Transform, &Velocity), With<Player>>, ) { for (mut transform, velocity) in &mut query { transform.translation.x += velocity.x * time.delta_seconds(); transform.translation.y += velocity.y * time.delta_seconds(); } }
3. Managing Resources
Use Resource for global data (score, game state).
#[derive(Resource)] struct GameState { score: u32, } fn score_system(mut game_state: ResMut<GameState>) { game_state.score += 10; }
4. Scheduling Systems
Add systems to the App builder, defining execution order if needed.
fn main() { App::new() .add_plugins(DefaultPlugins) .init_resource::<GameState>() .add_systems(Update, (movement_system, score_system).chain()) .run(); }
Examples
Example 1: Spawning Entities with Require Component
use bevy::prelude::*; #[derive(Component, Reflect, Default)] #[require(Velocity, Sprite)] struct Player; #[derive(Component, Default)] struct Velocity { x: f32, y: f32, } fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { commands.spawn(( Player, Velocity { x: 10.0, y: 0.0 }, Sprite::from_image(asset_server.load("player.png")), )); }
Example 2: Query Filters
Use With and Without to filter entities efficiently.
fn enemy_behavior( query: Query<&Transform, (With<Enemy>, Without<Dead>)>, ) { for transform in &query { // Only active enemies processed here } }
Best Practices
- ✅ Do: Use
Queryfilters (With,Without,Changed) to reduce iteration count. - ✅ Do: Prefer
ResoverResMutwhen read-only access is sufficient to allow parallel execution. - ✅ Do: Use
Bundleto spawn complex entities atomically. - ❌ Don't: Store heavy logic inside Components; keep them as pure data.
- ❌ Don't: Use
RefCellor interior mutability inside components; let the ECS handle borrowing.
Troubleshooting
Problem: System panic with "Conflict" error.
Solution: You are likely trying to access the same component mutably in two systems running in parallel. Use .chain() to order them or split the logic.