Relevant official examples: ecs_guide.


Entities

Entities are just a simple integer ID, that identifies a particular set of component values.

Components

Components are the data associated with entities.

Any Rust type (struct or enum) can be used as a component.

struct Health {
    hp: f32,
    extra: f32,
}

Types must be unique -- an entity can only have one component per Rust type.

Use wrapper (newtype) structs to make unique components out of simpler types:

struct PlayerXp(u32);

struct PlayerName(String);

You can use empty structs to mark specific entities. These are known as "marker components". Useful with query filters.

/// Add this to all menu ui entities to help identify them
struct MainMenuUI;
/// Marker to help identify the player
struct Player;
/// Marker for hostiles
struct Enemy;

Components can be accessed from systems, using queries.

Component Bundles

Bundles are like "templates", to make it easy to create entities with a common set of components.

#[derive(Bundle)]
struct PlayerBundle {
    xp: PlayerXp,
    name: PlayerName,
    health: Health,
    _p: Player,

    // We can nest/include another bundle.
    // Add the components for a standard Bevy Sprite:
    #[bundle]
    sprite: SpriteSheetBundle,
}

Bevy also considers arbitrary tuples of components as bundles:

(ComponentA, ComponentB, ComponentC)

Common Pitfalls

Because both bundles and individual components are regular Rust structs, Bevy / the Rust compiler often has no way to distinguish them.

If you accidentally use a bundle struct somewhere where Bevy expects a component, you will not get an error. Bevy will just treat it as a component of that struct type!

For example, this is why we needed the #[bundle] annotation to include a sub-bundle in the example above.

Other places where this issue may come up are: when using Commands, and when querying (queries only work with components!).