diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index fdcb2a0d0d..81246e186c 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -14,26 +14,102 @@ use std::{ mem::needs_drop, }; -/// A component is data associated with an [`Entity`](crate::entity::Entity). Each entity can have -/// multiple different types of components, but only one of them per type. +/// A data type that can be used to store data for an [entity]. /// -/// Any type that is `Send + Sync + 'static` can implement `Component` using `#[derive(Component)]`. /// -/// In order to use foreign types as components, wrap them using a newtype pattern. +/// `Component` is a [derivable trait]: this means that a data type can implement it by applying a `#[derive(Component)]` attribute to it. +/// However, components must always satisfy the `Send + Sync + 'static` trait bounds. +/// +/// [entity]: crate::entity +/// [derivable trait]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html +/// +/// # Examples +/// +/// Components can take many forms: they are usually structs, but can also be of every other kind of data type, like enums or zero sized types. +/// The following examples show how components are laid out in code. +/// /// ``` /// # use bevy_ecs::component::Component; +/// # struct Color; +/// # +/// // A component can contain data... +/// #[derive(Component)] +/// struct LicensePlate(String); +/// +/// // ... but it can also be a zero-sized marker. +/// #[derive(Component)] +/// struct Car; +/// +/// // Components can also be structs with named fields... +/// #[derive(Component)] +/// struct VehiclePerformance { +/// acceleration: f32, +/// top_speed: f32, +/// handling: f32, +/// } +/// +/// // ... or enums. +/// #[derive(Component)] +/// enum WheelCount { +/// Two, +/// Three, +/// Four, +/// } +/// ``` +/// +/// # Component and data access +/// +/// See the [`entity`] module level documentation to learn how to add or remove components from an entity. +/// +/// See the documentation for [`Query`] to learn how to access component data from a system. +/// +/// [`entity`]: crate::entity#usage +/// [`Query`]: crate::system::Query +/// +/// # Choosing a storage type +/// +/// Components can be stored in the world using different strategies with their own performance implications. +/// By default, components are added to the [`Table`] storage, which is optimized for query iteration. +/// +/// Alternatively, components can be added to the [`SparseSet`] storage, which is optimized for component insertion and removal. +/// This is achieved by adding an additional `#[component(storage = "SparseSet")]` attribute to the derive one: +/// +/// ``` +/// # use bevy_ecs::component::Component; +/// # +/// #[derive(Component)] +/// #[component(storage = "SparseSet")] +/// struct ComponentA; +/// ``` +/// +/// [`Table`]: crate::storage::Table +/// [`SparseSet`]: crate::storage::SparseSet +/// +/// # Implementing the trait for foreign types +/// +/// As a consequence of the [orphan rule], it is not possible to separate into two different crates the implementation of `Component` from the definition of a type. +/// This means that it is not possible to directly have a type defined in a third party library as a component. +/// This important limitation can be easily worked around using the [newtype pattern]: +/// this makes it possible to locally define and implement `Component` for a tuple struct that wraps the foreign type. +/// The following example gives a demonstration of this pattern. +/// +/// ``` +/// // `Component` is defined in the `bevy_ecs` crate. +/// use bevy_ecs::component::Component; +/// +/// // `Duration` is defined in the `std` crate. /// use std::time::Duration; +/// +/// // It is not possible to implement `Component` for `Duration` from this position, as they are +/// // both foreign items, defined in an external crate. However, nothing prevents to define a new +/// // `Cooldown` type that wraps `Duration`. As `Cooldown` is defined in a local crate, it is +/// // possible to implement `Component` for it. /// #[derive(Component)] /// struct Cooldown(Duration); /// ``` -/// Components are added with new entities using [`Commands::spawn`](crate::system::Commands::spawn), -/// or to existing entities with [`EntityCommands::insert`](crate::system::EntityCommands::insert), -/// or their [`World`](crate::world::World) equivalents. /// -/// Components can be accessed in systems by using a [`Query`](crate::system::Query) -/// as one of the arguments. -/// -/// Components can be grouped together into a [`Bundle`](crate::bundle::Bundle). +/// [orphan rule]: https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type +/// [newtype pattern]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types pub trait Component: Send + Sync + 'static { type Storage: ComponentStorage; } diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index abfd3513ea..dcad2664f6 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -1,27 +1,38 @@ //! Entity handling types. //! -//! In Bevy ECS, there is no monolithic data structure for an entity. Instead, the [`Entity`] -//! `struct` is just a *generational index* (a combination of an ID and a generation). Then, -//! the `Entity` maps to the specific [`Component`s](crate::component::Component). This way, -//! entities can have meaningful data attached to it. This is a fundamental design choice -//! that has been taken to enhance performance and usability. +//! An **entity** exclusively owns zero or more [component] instances, all of different types, and can dynamically acquire or lose them over its lifetime. +//! +//! See [`Entity`] to learn more. +//! +//! [component]: crate::component::Component //! //! # Usage //! -//! Here are links to the methods used to perform common operations -//! involving entities: +//! Operations involving entities and their components are performed either from a system by submitting commands, +//! or from the outside (or from an exclusive system) by directly using [`World`] methods: //! -//! - **Spawning an empty entity:** use [`Commands::spawn`](crate::system::Commands::spawn). -//! - **Spawning an entity with components:** use -//! [`Commands::spawn_bundle`](crate::system::Commands::spawn_bundle). -//! - **Despawning an entity:** use -//! [`EntityCommands::despawn`](crate::system::EntityCommands::despawn). -//! - **Inserting a component to an entity:** use -//! [`EntityCommands::insert`](crate::system::EntityCommands::insert). -//! - **Adding multiple components to an entity:** use -//! [`EntityCommands::insert_bundle`](crate::system::EntityCommands::insert_bundle). -//! - **Removing a component to an entity:** use -//! [`EntityCommands::remove`](crate::system::EntityCommands::remove). +//! |Operation|Command|Method| +//! |:---:|:---:|:---:| +//! |Spawn a new entity|[`Commands::spawn`]|[`World::spawn`]| +//! |Spawn an entity with components|[`Commands::spawn_bundle`]|---| +//! |Despawn an entity|[`EntityCommands::despawn`]|[`World::despawn`]| +//! |Insert a component to an entity|[`EntityCommands::insert`]|[`EntityMut::insert`]| +//! |Insert multiple components to an entity|[`EntityCommands::insert_bundle`]|[`EntityMut::insert_bundle`]| +//! |Remove a component from an entity|[`EntityCommands::remove`]|[`EntityMut::remove`]| +//! +//! [`World`]: crate::world::World +//! [`Commands::spawn`]: crate::system::Commands::spawn +//! [`Commands::spawn_bundle`]: crate::system::Commands::spawn_bundle +//! [`EntityCommands::despawn`]: crate::system::EntityCommands::despawn +//! [`EntityCommands::insert`]: crate::system::EntityCommands::insert +//! [`EntityCommands::insert_bundle`]: crate::system::EntityCommands::insert_bundle +//! [`EntityCommands::remove`]: crate::system::EntityCommands::remove +//! [`World::spawn`]: crate::world::World::spawn +//! [`World::spawn_bundle`]: crate::world::World::spawn_bundle +//! [`World::despawn`]: crate::world::World::despawn +//! [`EntityMut::insert`]: crate::world::EntityMut::insert +//! [`EntityMut::insert_bundle`]: crate::world::EntityMut::insert_bundle +//! [`EntityMut::remove`]: crate::world::EntityMut::remove mod map_entities; mod serde; @@ -35,15 +46,57 @@ use std::{ sync::atomic::{AtomicI64, Ordering}, }; -/// Lightweight unique ID of an entity. +/// Lightweight identifier of an [entity](crate::entity). /// -/// Obtained from [`World::spawn`](crate::world::World::spawn), typically via -/// [`Commands::spawn`](crate::system::Commands::spawn). Can be stored to refer to an entity in the -/// future. +/// The identifier is implemented using a [generational index]: a combination of an ID and a generation. +/// This allows fast insertion after data removal in an array while minimizing loss of spatial locality. /// -/// `Entity` can be a part of a query, e.g. `Query<(Entity, &MyComponent)>`. -/// Components of a specific entity can be accessed using -/// [`Query::get`](crate::system::Query::get) and related methods. +/// [generational index]: https://lucassardois.medium.com/generational-indices-guide-8e3c5f7fd594 +/// +/// # Usage +/// +/// This data type is returned by iterating a `Query` that has `Entity` as part of its query fetch type parameter ([learn more]). +/// It can also be obtained by calling [`EntityCommands::id`] or [`EntityMut::id`]. +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// # +/// fn setup(mut commands: Commands) { +/// // Calling `spawn` returns `EntityCommands`. +/// let entity = commands.spawn().id(); +/// } +/// +/// fn exclusive_system(world: &mut World) { +/// // Calling `spawn` returns `EntityMut`. +/// let entity = world.spawn().id(); +/// } +/// # +/// # bevy_ecs::system::assert_is_system(setup); +/// # bevy_ecs::system::IntoExclusiveSystem::exclusive_system(exclusive_system); +/// ``` +/// +/// It can be used to refer to a specific entity to apply [`EntityCommands`], or to call [`Query::get`] (or similar methods) to access its components. +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// # +/// # #[derive(Component)] +/// # struct Expired; +/// # +/// fn dispose_expired_food(mut commands: Commands, query: Query>) { +/// for food_entity in query.iter() { +/// commands.entity(food_entity).despawn(); +/// } +/// } +/// # +/// # bevy_ecs::system::assert_is_system(dispose_expired_food); +/// ``` +/// +/// [learn more]: crate::system::Query#entity-id-access +/// [`EntityCommands::id`]: crate::system::EntityCommands::id +/// [`EntityMut::id`]: crate::world::EntityMut::id +/// [`EntityCommands`]: crate::system::EntityCommands +/// [`Query::get`]: crate::system::Query::get #[derive(Clone, Copy, Hash, Eq, Ord, PartialEq, PartialOrd)] pub struct Entity { pub(crate) generation: u32,