Skip to content

Commit 511bcc9

Browse files
committed
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]: #4767 (comment) [Resolved]: #4767 (comment)
1 parent c4fc5d8 commit 511bcc9

File tree

2 files changed

+165
-36
lines changed

2 files changed

+165
-36
lines changed

crates/bevy_ecs/src/component.rs

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,102 @@ use std::{
1414
mem::needs_drop,
1515
};
1616

17-
/// A component is data associated with an [`Entity`](crate::entity::Entity). Each entity can have
18-
/// multiple different types of components, but only one of them per type.
17+
/// A data type that can be used to store data for an [entity].
1918
///
20-
/// Any type that is `Send + Sync + 'static` can implement `Component` using `#[derive(Component)]`.
2119
///
22-
/// In order to use foreign types as components, wrap them using a newtype pattern.
20+
/// `Component` is a [derivable trait]: this means that a data type can implement it by applying a `#[derive(Component)]` attribute to it.
21+
/// However, components must always satisfy the `Send + Sync + 'static` trait bounds.
22+
///
23+
/// [entity]: crate::entity
24+
/// [derivable trait]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html
25+
///
26+
/// # Examples
27+
///
28+
/// 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.
29+
/// The following examples show how components are laid out in code.
30+
///
31+
/// ```
32+
/// # use bevy_ecs::component::Component;
33+
/// # struct Color;
34+
/// #
35+
/// // A component can contain data...
36+
/// #[derive(Component)]
37+
/// struct LicensePlate(String);
38+
///
39+
/// // ... but it can also be a zero-sized marker.
40+
/// #[derive(Component)]
41+
/// struct Car;
42+
///
43+
/// // Components can also be structs with named fields...
44+
/// #[derive(Component)]
45+
/// struct VehiclePerformance {
46+
/// acceleration: f32,
47+
/// top_speed: f32,
48+
/// handling: f32,
49+
/// }
50+
///
51+
/// // ... or enums.
52+
/// #[derive(Component)]
53+
/// enum WheelCount {
54+
/// Two,
55+
/// Three,
56+
/// Four,
57+
/// }
58+
/// ```
59+
///
60+
/// # Component and data access
61+
///
62+
/// See the [`entity`] module level documentation to learn how to add or remove components from an entity.
63+
///
64+
/// See the documentation for [`Query`] to learn how to access component data from a system.
65+
///
66+
/// [`entity`]: crate::entity#usage
67+
/// [`Query`]: crate::system::Query
68+
///
69+
/// # Choosing a storage type
70+
///
71+
/// Components can be stored in the world using different strategies with their own performance implications.
72+
/// By default, components are added to the [`Table`] storage, which is optimized for query iteration.
73+
///
74+
/// Alternatively, components can be added to the [`SparseSet`] storage, which is optimized for component insertion and removal.
75+
/// This is achieved by adding an additional `#[component(storage = "SparseSet")]` attribute to the derive one:
76+
///
2377
/// ```
2478
/// # use bevy_ecs::component::Component;
79+
/// #
80+
/// #[derive(Component)]
81+
/// #[component(storage = "SparseSet")]
82+
/// struct ComponentA;
83+
/// ```
84+
///
85+
/// [`Table`]: crate::storage::Table
86+
/// [`SparseSet`]: crate::storage::SparseSet
87+
///
88+
/// # Implementing the trait for foreign types
89+
///
90+
/// 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.
91+
/// This means that it is not possible to directly have a type defined in a third party library as a component.
92+
/// This important limitation can be easily worked around using the [newtype pattern]:
93+
/// this makes it possible to locally define and implement `Component` for a tuple struct that wraps the foreign type.
94+
/// The following example gives a demonstration of this pattern.
95+
///
96+
/// ```
97+
/// // `Component` is defined in the `bevy_ecs` crate.
98+
/// use bevy_ecs::component::Component;
99+
///
100+
/// // `Duration` is defined in the `std` crate.
25101
/// use std::time::Duration;
102+
///
103+
/// // It is not possible to implement `Component` for `Duration` from this position, as they are
104+
/// // both foreign items, defined in an external crate. However, nothing prevents to define a new
105+
/// // `Cooldown` type that wraps `Duration`. As `Cooldown` is defined in a local crate, it is
106+
/// // possible to implement `Component` for it.
26107
/// #[derive(Component)]
27108
/// struct Cooldown(Duration);
28109
/// ```
29-
/// Components are added with new entities using [`Commands::spawn`](crate::system::Commands::spawn),
30-
/// or to existing entities with [`EntityCommands::insert`](crate::system::EntityCommands::insert),
31-
/// or their [`World`](crate::world::World) equivalents.
32-
///
33-
/// Components can be accessed in systems by using a [`Query`](crate::system::Query)
34-
/// as one of the arguments.
35110
///
36-
/// Components can be grouped together into a [`Bundle`](crate::bundle::Bundle).
111+
/// [orphan rule]: https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type
112+
/// [newtype pattern]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types
37113
pub trait Component: Send + Sync + 'static {
38114
type Storage: ComponentStorage;
39115
}

crates/bevy_ecs/src/entity/mod.rs

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,38 @@
11
//! Entity handling types.
22
//!
3-
//! In Bevy ECS, there is no monolithic data structure for an entity. Instead, the [`Entity`]
4-
//! `struct` is just a *generational index* (a combination of an ID and a generation). Then,
5-
//! the `Entity` maps to the specific [`Component`s](crate::component::Component). This way,
6-
//! entities can have meaningful data attached to it. This is a fundamental design choice
7-
//! that has been taken to enhance performance and usability.
3+
//! An **entity** exclusively owns zero or more [component] instances, all of different types, and can dynamically acquire or lose them over its lifetime.
4+
//!
5+
//! See [`Entity`] to learn more.
6+
//!
7+
//! [component]: crate::component::Component
88
//!
99
//! # Usage
1010
//!
11-
//! Here are links to the methods used to perform common operations
12-
//! involving entities:
11+
//! Operations involving entities and their components are performed either from a system by submitting commands,
12+
//! or from the outside (or from an exclusive system) by directly using [`World`] methods:
13+
//!
14+
//! |Operation|Command|Method|
15+
//! |:---:|:---:|:---:|
16+
//! |Spawn a new entity|[`Commands::spawn`]|[`World::spawn`]|
17+
//! |Spawn an entity with components|[`Commands::spawn_bundle`]|---|
18+
//! |Despawn an entity|[`EntityCommands::despawn`]|[`World::despawn`]|
19+
//! |Insert a component to an entity|[`EntityCommands::insert`]|[`EntityMut::insert`]|
20+
//! |Insert multiple components to an entity|[`EntityCommands::insert_bundle`]|[`EntityMut::insert_bundle`]|
21+
//! |Remove a component from an entity|[`EntityCommands::remove`]|[`EntityMut::remove`]|
1322
//!
14-
//! - **Spawning an empty entity:** use [`Commands::spawn`](crate::system::Commands::spawn).
15-
//! - **Spawning an entity with components:** use
16-
//! [`Commands::spawn_bundle`](crate::system::Commands::spawn_bundle).
17-
//! - **Despawning an entity:** use
18-
//! [`EntityCommands::despawn`](crate::system::EntityCommands::despawn).
19-
//! - **Inserting a component to an entity:** use
20-
//! [`EntityCommands::insert`](crate::system::EntityCommands::insert).
21-
//! - **Adding multiple components to an entity:** use
22-
//! [`EntityCommands::insert_bundle`](crate::system::EntityCommands::insert_bundle).
23-
//! - **Removing a component to an entity:** use
24-
//! [`EntityCommands::remove`](crate::system::EntityCommands::remove).
23+
//! [`World`]: crate::world::World
24+
//! [`Commands::spawn`]: crate::system::Commands::spawn
25+
//! [`Commands::spawn_bundle`]: crate::system::Commands::spawn_bundle
26+
//! [`EntityCommands::despawn`]: crate::system::EntityCommands::despawn
27+
//! [`EntityCommands::insert`]: crate::system::EntityCommands::insert
28+
//! [`EntityCommands::insert_bundle`]: crate::system::EntityCommands::insert_bundle
29+
//! [`EntityCommands::remove`]: crate::system::EntityCommands::remove
30+
//! [`World::spawn`]: crate::world::World::spawn
31+
//! [`World::spawn_bundle`]: crate::world::World::spawn_bundle
32+
//! [`World::despawn`]: crate::world::World::despawn
33+
//! [`EntityMut::insert`]: crate::world::EntityMut::insert
34+
//! [`EntityMut::insert_bundle`]: crate::world::EntityMut::insert_bundle
35+
//! [`EntityMut::remove`]: crate::world::EntityMut::remove
2536
mod map_entities;
2637
mod serde;
2738

@@ -35,15 +46,57 @@ use std::{
3546
sync::atomic::{AtomicI64, Ordering},
3647
};
3748

38-
/// Lightweight unique ID of an entity.
49+
/// Lightweight identifier of an [entity](crate::entity).
50+
///
51+
/// The identifier is implemented using a [generational index]: a combination of an ID and a generation.
52+
/// This allows fast insertion after data removal in an array while minimizing loss of spatial locality.
53+
///
54+
/// [generational index]: https://lucassardois.medium.com/generational-indices-guide-8e3c5f7fd594
55+
///
56+
/// # Usage
57+
///
58+
/// This data type is returned by iterating a `Query` that has `Entity` as part of its query fetch type parameter ([learn more]).
59+
/// It can also be obtained by calling [`EntityCommands::id`] or [`EntityMut::id`].
60+
///
61+
/// ```
62+
/// # use bevy_ecs::prelude::*;
63+
/// #
64+
/// fn setup(mut commands: Commands) {
65+
/// // Calling `spawn` returns `EntityCommands`.
66+
/// let entity = commands.spawn().id();
67+
/// }
68+
///
69+
/// fn exclusive_system(world: &mut World) {
70+
/// // Calling `spawn` returns `EntityMut`.
71+
/// let entity = world.spawn().id();
72+
/// }
73+
/// #
74+
/// # bevy_ecs::system::assert_is_system(setup);
75+
/// # bevy_ecs::system::IntoExclusiveSystem::exclusive_system(exclusive_system);
76+
/// ```
77+
///
78+
/// 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.
3979
///
40-
/// Obtained from [`World::spawn`](crate::world::World::spawn), typically via
41-
/// [`Commands::spawn`](crate::system::Commands::spawn). Can be stored to refer to an entity in the
42-
/// future.
80+
/// ```
81+
/// # use bevy_ecs::prelude::*;
82+
/// #
83+
/// # #[derive(Component)]
84+
/// # struct Expired;
85+
/// #
86+
/// fn dispose_expired_food(mut commands: Commands, query: Query<Entity, With<Expired>>) {
87+
/// for food_entity in query.iter() {
88+
/// commands.entity(food_entity).despawn();
89+
/// }
90+
/// }
91+
/// #
92+
/// # bevy_ecs::system::assert_is_system(dispose_expired_food);
93+
/// ```
4394
///
44-
/// `Entity` can be a part of a query, e.g. `Query<(Entity, &MyComponent)>`.
45-
/// Components of a specific entity can be accessed using
46-
/// [`Query::get`](crate::system::Query::get) and related methods.
95+
/// [learn more]: crate::system::Query#entity-id-access
96+
/// [`EntityCommands::id`]: crate::system::EntityCommands::id
97+
/// [`EntityMut::id`]: crate::world::EntityMut::id
98+
/// [`EntityCommands`]: crate::system::EntityCommands
99+
/// [`Query::get`]: crate::system::Query::get
47100
#[derive(Clone, Copy, Hash, Eq, Ord, PartialEq, PartialOrd)]
48101
pub struct Entity {
49102
pub(crate) generation: u32,

0 commit comments

Comments
 (0)