The App

Relevant official examples: All of them ;)

In particular, check out the complete game examples: alien_cake_addict, breakout.


To enter the bevy runtime, you need to configure an App. The app is how you define the structure of all the things that make up your project: plugins, systems (and their configuration/metadata), event types, states, schedules

Technically, the App is what brings the whole ECS together. It contains the World(s) (where all the data is stored), the Schedule(s) (where all the functionality is stored and configured), and the "runner", which is the code that is responsible for running everything.

You typically create your App in your project's main function. However, you don't have to add everything from there. If you want to add things to your app from multiple places (like other Rust files or crates), use plugins. As your project grows, you will need to do that to keep everything organized.

fn main() {
    App::new()
        // Bevy itself:
        .add_plugins(DefaultPlugins)

        // events:
        .add_event::<LevelUpEvent>()

        // systems to run once at startup:
        .add_systems(Startup, spawn_things)

        // systems to run each frame:
        .add_systems(Update, (
            player_level_up,
            debug_levelups,
            debug_stats_change,
        ))
        // ...

        // launch the app!
        .run();
}

Note: add_systems and add_plugins allow you to add multiple things at once, using tuple syntax.

Local resources do not need to be registered. They are part of their respective systems.

Component types do not need to be registered.

Schedules cannot (yet) be modified at runtime; all systems you want to run must be added/configured in the App ahead of time. You can control individual systems using run conditions. You can also dynamically enable/disable entire schedules using the MainScheduleOrder resource.

Builtin Bevy Functionality

The Bevy game engine's own functionality is represented as a plugin group. Every typical Bevy app must first add it, using either:

Setting up data

Normally, you can set up your data from systems. Use Commands from regular systems, or use exclusive systems to get full World access.

Add your setup systems as startup systems for things you want to initialize at launch, or use state enter/exit systems to do things when transitioning between menus, game modes, levels, etc.

However, you can also initialize data directly from the app builder. This is common for resources, if they need to be present at all times. You can also get direct World access.

// Create (or overwrite) resource with specific value
app.insert_resource(StartingLevel(3));

// Ensure resource exists; if not, create it
// (using `Default` or `FromWorld`)
app.init_resource::<MyFancyResource>();

// We can also access/manipulate the World directly
// (in this example, to spawn an entity, but you can do anything)
app.world.spawn(SomeBundle::default());

Quitting the App

To cleanly shut down bevy, send an AppExit event from any system:

use bevy::app::AppExit;

fn exit_system(mut exit: EventWriter<AppExit>) {
    exit.send(AppExit);
}

For prototyping, Bevy provides a convenient system you can add, to close the focused window on pressing the Esc key. When all windows are closed, Bevy will quit automatically.

app.add_systems(Update, bevy::window::close_on_esc);