diff --git a/crates/bevy_animation/src/animation_curves.rs b/crates/bevy_animation/src/animation_curves.rs index 9fb92b36b3..be68c93576 100644 --- a/crates/bevy_animation/src/animation_curves.rs +++ b/crates/bevy_animation/src/animation_curves.rs @@ -105,38 +105,43 @@ use bevy_platform_support::hash::Hashed; use bevy_reflect::{FromReflect, Reflect, Reflectable, TypeInfo, Typed}; use downcast_rs::{impl_downcast, Downcast}; -/// A value on a component that Bevy can animate. +/// A trait for exposing a value in an entity so that it can be animated. /// -/// You can implement this trait on a unit struct in order to support animating -/// custom components other than transforms and morph weights. Use that type in -/// conjunction with [`AnimatableCurve`] (and perhaps [`AnimatableKeyframeCurve`] -/// to define the animation itself). -/// For example, in order to animate field of view, you might use: +/// `AnimatableProperty` allows any value contained in an entity to be animated +/// as long as it can be obtained by mutable reference. This makes it more +/// flexible than [`animated_field`]. +/// +/// [`animated_field`]: crate::animated_field +/// +/// Here, `AnimatableProperty` is used to animate a value inside an `Option`, +/// returning an error if the option is `None`. /// /// # use bevy_animation::{prelude::AnimatableProperty, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId}; -/// # use bevy_reflect::Reflect; +/// # use bevy_ecs::component::Component; /// # use std::any::TypeId; -/// # use bevy_render::camera::{Projection, PerspectiveProjection}; -/// #[derive(Reflect)] -/// struct FieldOfViewProperty; +/// #[derive(Component)] +/// struct ExampleComponent { +/// power_level: Option +/// } /// -/// impl AnimatableProperty for FieldOfViewProperty { +/// #[derive(Clone)] +/// struct PowerLevelProperty; +/// +/// impl AnimatableProperty for PowerLevelProperty { /// type Property = f32; -/// fn get_mut<'a>(&self, entity: &'a mut AnimationEntityMut) -> Result<&'a mut Self::Property, AnimationEvaluationError> { +/// fn get_mut<'a>( +/// &self, +/// entity: &'a mut AnimationEntityMut +/// ) -> Result<&'a mut Self::Property, AnimationEvaluationError> { /// let component = entity -/// .get_mut::() -/// .ok_or(AnimationEvaluationError::ComponentNotPresent(TypeId::of::< -/// Projection, -/// >( -/// )))? +/// .get_mut::() +/// .ok_or(AnimationEvaluationError::ComponentNotPresent( +/// TypeId::of::() +/// ))? /// .into_inner(); -/// match component { -/// Projection::Perspective(perspective) => Ok(&mut perspective.fov), -/// _ => Err(AnimationEvaluationError::PropertyNotPresent(TypeId::of::< -/// PerspectiveProjection, -/// >( -/// ))), -/// } +/// component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent( +/// TypeId::of::>() +/// )) /// } /// /// fn evaluator_id(&self) -> EvaluatorId { @@ -144,58 +149,44 @@ use downcast_rs::{impl_downcast, Downcast}; /// } /// } /// -/// You can then create an [`AnimationClip`] to animate this property like so: /// -/// # use bevy_animation::{AnimationClip, AnimationTargetId, VariableCurve, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId}; +/// You can then create an [`AnimatableCurve`] to animate this property like so: +/// +/// # use bevy_animation::{VariableCurve, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId}; /// # use bevy_animation::prelude::{AnimatableProperty, AnimatableKeyframeCurve, AnimatableCurve}; -/// # use bevy_ecs::name::Name; -/// # use bevy_reflect::Reflect; -/// # use bevy_render::camera::{Projection, PerspectiveProjection}; +/// # use bevy_ecs::{name::Name, component::Component}; /// # use std::any::TypeId; -/// # let animation_target_id = AnimationTargetId::from(&Name::new("Test")); -/// # #[derive(Reflect, Clone)] -/// # struct FieldOfViewProperty; -/// # impl AnimatableProperty for FieldOfViewProperty { -/// # type Property = f32; -/// # fn get_mut<'a>(&self, entity: &'a mut AnimationEntityMut) -> Result<&'a mut Self::Property, AnimationEvaluationError> { -/// # let component = entity -/// # .get_mut::() -/// # .ok_or(AnimationEvaluationError::ComponentNotPresent(TypeId::of::< -/// # Projection, -/// # >( -/// # )))? -/// # .into_inner(); -/// # match component { -/// # Projection::Perspective(perspective) => Ok(&mut perspective.fov), -/// # _ => Err(AnimationEvaluationError::PropertyNotPresent(TypeId::of::< -/// # PerspectiveProjection, -/// # >( -/// # ))), -/// # } -/// # } -/// # fn evaluator_id(&self) -> EvaluatorId { -/// # EvaluatorId::Type(TypeId::of::()) -/// # } +/// # #[derive(Component)] +/// # struct ExampleComponent { power_level: Option } +/// # #[derive(Clone)] +/// # struct PowerLevelProperty; +/// # impl AnimatableProperty for PowerLevelProperty { +/// # type Property = f32; +/// # fn get_mut<'a>( +/// # &self, +/// # entity: &'a mut AnimationEntityMut +/// # ) -> Result<&'a mut Self::Property, AnimationEvaluationError> { +/// # let component = entity +/// # .get_mut::() +/// # .ok_or(AnimationEvaluationError::ComponentNotPresent( +/// # TypeId::of::() +/// # ))? +/// # .into_inner(); +/// # component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent( +/// # TypeId::of::>() +/// # )) +/// # } +/// # fn evaluator_id(&self) -> EvaluatorId { +/// # EvaluatorId::Type(TypeId::of::()) +/// # } /// # } -/// let mut animation_clip = AnimationClip::default(); -/// animation_clip.add_curve_to_target( -/// animation_target_id, -/// AnimatableCurve::new( -/// FieldOfViewProperty, -/// AnimatableKeyframeCurve::new([ -/// (0.0, core::f32::consts::PI / 4.0), -/// (1.0, core::f32::consts::PI / 3.0), -/// ]).expect("Failed to create font size curve") -/// ) +/// AnimatableCurve::new( +/// PowerLevelProperty, +/// AnimatableKeyframeCurve::new([ +/// (0.0, 0.0), +/// (1.0, 9001.0), +/// ]).expect("Failed to create power level curve") /// ); -/// -/// Here, the use of [`AnimatableKeyframeCurve`] creates a curve out of the given keyframe time-value -/// pairs, using the [`Animatable`] implementation of `f32` to interpolate between them. The -/// invocation of [`AnimatableCurve::new`] with `FieldOfViewProperty` indicates that the `f32` -/// output from that curve is to be used to animate the font size of a `PerspectiveProjection` component (as -/// configured above). -/// -/// [`AnimationClip`]: crate::AnimationClip pub trait AnimatableProperty: Send + Sync + 'static { /// The animated property type. type Property: Animatable;