Improve entity and component API docs (#4767)
# Objective The descriptions included in the API docs of `entity` module, `Entity` struct, and `Component` trait have some issues: 1. the concept of entity is not clearly defined, 2. descriptions are a little bit out of place, 3. in a case the description leak too many details about the implementation, 4. some descriptions are not exhaustive, 5. there are not enough examples, 6. the content can be formatted in a much better way. ## Solution 1. ~~Stress the fact that entity is an abstract and elementary concept. Abstract because the concept of entity is not hardcoded into the library but emerges from the interaction of `Entity` with every other part of `bevy_ecs`, like components and world methods. Elementary because it is a fundamental concept that cannot be defined with other terms (like point in euclidean geometry, or time in classical physics).~~ We decided to omit the definition of entity in the API docs ([see why]). It is only described in its relationship with components. 2. Information has been moved to relevant places and links are used instead in the other places. 3. Implementation details about `Entity` have been reduced. 4. Descriptions have been made more exhaustive by stating how to obtain and use items. Entity operations are enriched with `World` methods. 5. Examples have been added or enriched. 6. Sections have been added to organize content. Entity operations are now laid out in a table. ### Todo list - [x] Break lines at sentence-level. ## For reviewers - ~~I added a TODO over `Component` docs, make sure to check it out and discuss it if necessary.~~ ([Resolved]) - You can easily check the rendered documentation by doing `cargo doc -p bevy_ecs --no-deps --open`. [see why]: https://github.com/bevyengine/bevy/pull/4767#discussion_r875106329 [Resolved]: https://github.com/bevyengine/bevy/pull/4767#discussion_r874127825
This commit is contained in:
		
							parent
							
								
									c4fc5d88f0
								
							
						
					
					
						commit
						511bcc9633
					
				@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<Entity, With<Expired>>) {
 | 
			
		||||
///     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,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user