Bevy Engine
Entities, components, systems, and schedules - the Bevy ECS game engine in Rust.
Recipe
use bevy::prelude::*;
#[derive(Component)]
struct Velocity(Vec2);
fn move_system(mut query: Query<(&mut Transform, &Velocity)>, time: Res<Time>) {
for (mut transform, velocity) in &mut query {
transform.translation += velocity.0.extend(0.0) * time.delta_secs();
}
}When to reach for this:
- 2D/3D games wanting data-oriented Rust engine
- Prototyping with hot reload and strong ECS patterns
- Tools simulating many agents with parallel systems
- Learning ECS without building engine infrastructure
Working Example
use bevy::prelude::*;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Velocity(Vec2);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, (player_input, move_system))
.run();
}
fn setup(mut commands: Commands) {
commands.spawn((Player, Velocity(Vec2::ZERO), Transform::default()));
commands.spawn(Camera2d);
}
fn player_input(
keys: Res<ButtonInput<KeyCode>>,
mut q: Query<&mut Velocity, With<Player>>,
) {
let mut v = Vec2::ZERO;
if keys.pressed(KeyCode::KeyW) { v.y += 1.0; }
if keys.pressed(KeyCode::KeyS) { v.y -= 1.0; }
if keys.pressed(KeyCode::KeyA) { v.x -= 1.0; }
if keys.pressed(KeyCode::KeyD) { v.x += 1.0; }
for mut vel in &mut q {
vel.0 = v.normalize_or_zero() * 300.0;
}
}
fn move_system(mut query: Query<(&mut Transform, &Velocity)>, time: Res<Time>) {
for (mut t, v) in &mut query {
t.translation += v.0.extend(0.0) * time.delta_secs();
}
}What this demonstrates:
- Input system writes
Velocity; movement system reads it With<Player>filter targets player entity- Delta-time scaled translation in
Update
Deep Dive
How It Works
- World stores entities, components, resources.
- Schedule orders systems; executor runs non-conflicting queries in parallel.
- Commands deferred structural changes (spawn/despawn/insert).
- Plugins register systems, assets, and render nodes modularly.
ECS Building Blocks
| Piece | Role |
|---|---|
| Entity | ID handle |
| Component | Data on entity |
| System | Function querying world |
| Resource | Global singleton (Time, Assets) |
Gotchas
- Query conflicts - two systems mutably accessing same component without ordering fail scheduler. Fix: chain with
.before/.afteror merge systems. - Spawn after despawn same frame - entity ID reuse confusion. Fix: use commands buffer semantics; avoid holding Entity across frames without validation.
- Huge monolithic systems - kills parallelism. Fix: split by component subsets.
- Assuming asset loaded instantly - pink placeholders. Fix: check
LoadStateor useSceneBundlewhen ready. - Bevy version drift - tutorial API mismatches. Fix: match book to exact crate version.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| macroquad | Tiny 2D jam games | Need full 3D render graph |
| Fyrox | Editor-heavy 3D | Want ECS-first minimalism |
| Custom wgpu | Total control | Time-to-fun priority |
| Godot + Rust GDExtension | Designer workflow | Pure Rust stack |
FAQs
2D vs 3D?
Bevy supports both via Camera2d/Camera3d and respective bundles - same ECS patterns.
How to order systems?
SystemSet labels and ordering constraints on Update, FixedUpdate, PostUpdate schedules.
Scene saving?
DynamicScene with reflected components serializes entity subsets - not all components reflect by default.
UI in Bevy?
bevy_ui for retained UI nodes; egui overlay via bevy_egui for debug tools.
Networking?
Community crates (bevy_replicon, etc.) - not in core; plan architecture early for multiplayer.
Performance?
See Performance for Games for profiling and data layout.
Physics?
avian or bevy_rapier plugins integrate with FixedUpdate - see physics page.
Audio?
bevy_audio with handles from asset server - see Physics & Audio.
Input?
Input & Events for actions and gamepad.
Lower-level rendering?
Graphics with wgpu when custom passes needed.
Related
- Game Dev Basics - orientation
- Assets & Scenes - loading
- Game Loops & Timing - schedules
- Performance for Games - optimization
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.