Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d6f56bd
Improve entity and component API docs
Nilirad May 16, 2022
897ef61
Fix doc error
Nilirad May 16, 2022
392a35f
Remove TODO about foreign type `Component` impl
Nilirad May 17, 2022
509794a
Improve wording for Component definition
Nilirad May 17, 2022
a14e051
Apply suggestion on `Component` trait bounds
Nilirad May 17, 2022
55039b8
Fix line breaks
Nilirad May 17, 2022
f347989
Line break on a sentence-level basis
Nilirad May 17, 2022
03d89db
Update crates/bevy_ecs/src/entity/mod.rs
Nilirad May 17, 2022
5d06e38
Reword `Entity` usage
Nilirad May 17, 2022
5bdb80b
Add external link about generational indices
Nilirad May 17, 2022
7267848
Reword ownership of a component
Nilirad May 17, 2022
5f8274c
Define link to `WorldQuery`
Nilirad May 17, 2022
0147802
Trim `entity` description
Nilirad May 17, 2022
e71bf0b
Add `Component` enum example
Nilirad May 17, 2022
dc93bbc
Remove excessive space
Nilirad May 17, 2022
ae1b302
Break all doc comments at sentence or clause level
Nilirad May 17, 2022
b4b95cd
Reword `Entity` access by querying
Nilirad May 18, 2022
bc45807
Use query fetch type parameter name
Nilirad May 18, 2022
2926989
Remove negative value line about component
Nilirad Jun 11, 2022
9b991aa
Document component storage choice
Nilirad Jun 20, 2022
d956aea
Remove relative language from `Component` examples
Nilirad Jun 21, 2022
3224296
Remove unused reference link
Nilirad Jun 21, 2022
498b689
Remove subjective language from `Component` description
Nilirad Jun 21, 2022
607e6bd
Update crates/bevy_ecs/src/component.rs
Nilirad Jun 21, 2022
a0421c6
Make it possible
Nilirad Jun 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 87 additions & 11 deletions crates/bevy_ecs/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is completely irrelevant, but I don't like using cars as examples

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried with people before publishing the PR, but I was struggling to not come up with stereotypes lol 🤣

///
/// // 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are those comments really useful? This information is already in the path. Same comment for Duration

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added those comments to make the line of thought explicit about explaining the orphan rule in the context of deriving Component

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to say this should be more explicit, but I can't figure out something to suggest so 🤷‍♂️. I'm fine with it either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In any case, this is a temporary solution until the new book includes it and it gets merged. Then it will be removed.

/// 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;
}
Expand Down
103 changes: 78 additions & 25 deletions crates/bevy_ecs/src/entity/mod.rs
Original file line number Diff line number Diff line change
@@ -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:
//!
//! |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`]|
//!
//! - **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).
//! [`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;

Expand All @@ -35,15 +46,57 @@ use std::{
sync::atomic::{AtomicI64, Ordering},
};

/// Lightweight unique ID of an entity.
/// Lightweight identifier of an [entity](crate::entity).
///
/// 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.
///
/// [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.
///
/// 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.
/// ```
/// # 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);
/// ```
///
/// `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.
/// [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,
Expand Down