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 Query filters ( With , Without , Changed ) to reduce iteration count. ✅ Do: Prefer Res over ResMut when read-only access is sufficient to allow parallel execution. ✅ Do: Use Bundle to spawn complex entities atomically. ❌ Don't: Store heavy logic inside Components; keep them as pure data. ❌ Don't: Use RefCell or 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.