Update AnimatableProperty
documentation, reduce crate dependencies (#18543)
## Objective - Remove the second to last `bevy_animation` dependency on `bevy_render`. - Update some older documentation to reflect later changes to the crate. ## Narrative I'm trying to make `bevy_animation` independent of `bevy_render`. The documentation for `bevy_animation::AnimatableProperty` is one of the last few dependencies. It uses `bevy_render::Projection` to demonstrate animating an arbitrary value, but I thought that could be easily swapped for something else. I then realised that the rest of the documentation was a bit out of date. Originally `AnimatableProperty` was the only way to animate a property and so the documentation was quite detailed. But over time the crate has gained more documentation and other ways to hook up properties, leaving parts of the docs stale or covered elsewhere. So I've slimmed down the `AnimatableProperty` docs and added a link to the main alternative (`animated_field`). I've probably swung too far towards brevity, so I can build them back up if preferred. Also the example is kinda contrived and doesn't show the range of `AnimatableProperty`, like being able to choose different components. And finally the memes might be a bit stale? ## Showcase  ## Testing ``` cargo doc -p bevy_animation --no-deps --all-features cargo test -p bevy_animation --doc --all-features ```
This commit is contained in:
parent
5d1fe16bfd
commit
a02cdaa017
@ -105,38 +105,43 @@ use bevy_platform_support::hash::Hashed;
|
|||||||
use bevy_reflect::{FromReflect, Reflect, Reflectable, TypeInfo, Typed};
|
use bevy_reflect::{FromReflect, Reflect, Reflectable, TypeInfo, Typed};
|
||||||
use downcast_rs::{impl_downcast, Downcast};
|
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
|
/// `AnimatableProperty` allows any value contained in an entity to be animated
|
||||||
/// custom components other than transforms and morph weights. Use that type in
|
/// as long as it can be obtained by mutable reference. This makes it more
|
||||||
/// conjunction with [`AnimatableCurve`] (and perhaps [`AnimatableKeyframeCurve`]
|
/// flexible than [`animated_field`].
|
||||||
/// to define the animation itself).
|
///
|
||||||
/// For example, in order to animate field of view, you might use:
|
/// [`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_animation::{prelude::AnimatableProperty, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId};
|
||||||
/// # use bevy_reflect::Reflect;
|
/// # use bevy_ecs::component::Component;
|
||||||
/// # use std::any::TypeId;
|
/// # use std::any::TypeId;
|
||||||
/// # use bevy_render::camera::{Projection, PerspectiveProjection};
|
/// #[derive(Component)]
|
||||||
/// #[derive(Reflect)]
|
/// struct ExampleComponent {
|
||||||
/// struct FieldOfViewProperty;
|
/// power_level: Option<f32>
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// impl AnimatableProperty for FieldOfViewProperty {
|
/// #[derive(Clone)]
|
||||||
|
/// struct PowerLevelProperty;
|
||||||
|
///
|
||||||
|
/// impl AnimatableProperty for PowerLevelProperty {
|
||||||
/// type Property = f32;
|
/// 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
|
/// let component = entity
|
||||||
/// .get_mut::<Projection>()
|
/// .get_mut::<ExampleComponent>()
|
||||||
/// .ok_or(AnimationEvaluationError::ComponentNotPresent(TypeId::of::<
|
/// .ok_or(AnimationEvaluationError::ComponentNotPresent(
|
||||||
/// Projection,
|
/// TypeId::of::<ExampleComponent>()
|
||||||
/// >(
|
/// ))?
|
||||||
/// )))?
|
|
||||||
/// .into_inner();
|
/// .into_inner();
|
||||||
/// match component {
|
/// component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent(
|
||||||
/// Projection::Perspective(perspective) => Ok(&mut perspective.fov),
|
/// TypeId::of::<Option<f32>>()
|
||||||
/// _ => Err(AnimationEvaluationError::PropertyNotPresent(TypeId::of::<
|
/// ))
|
||||||
/// PerspectiveProjection,
|
|
||||||
/// >(
|
|
||||||
/// ))),
|
|
||||||
/// }
|
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn evaluator_id(&self) -> EvaluatorId {
|
/// 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_animation::prelude::{AnimatableProperty, AnimatableKeyframeCurve, AnimatableCurve};
|
||||||
/// # use bevy_ecs::name::Name;
|
/// # use bevy_ecs::{name::Name, component::Component};
|
||||||
/// # use bevy_reflect::Reflect;
|
|
||||||
/// # use bevy_render::camera::{Projection, PerspectiveProjection};
|
|
||||||
/// # use std::any::TypeId;
|
/// # use std::any::TypeId;
|
||||||
/// # let animation_target_id = AnimationTargetId::from(&Name::new("Test"));
|
/// # #[derive(Component)]
|
||||||
/// # #[derive(Reflect, Clone)]
|
/// # struct ExampleComponent { power_level: Option<f32> }
|
||||||
/// # struct FieldOfViewProperty;
|
/// # #[derive(Clone)]
|
||||||
/// # impl AnimatableProperty for FieldOfViewProperty {
|
/// # struct PowerLevelProperty;
|
||||||
/// # type Property = f32;
|
/// # impl AnimatableProperty for PowerLevelProperty {
|
||||||
/// # fn get_mut<'a>(&self, entity: &'a mut AnimationEntityMut) -> Result<&'a mut Self::Property, AnimationEvaluationError> {
|
/// # type Property = f32;
|
||||||
/// # let component = entity
|
/// # fn get_mut<'a>(
|
||||||
/// # .get_mut::<Projection>()
|
/// # &self,
|
||||||
/// # .ok_or(AnimationEvaluationError::ComponentNotPresent(TypeId::of::<
|
/// # entity: &'a mut AnimationEntityMut
|
||||||
/// # Projection,
|
/// # ) -> Result<&'a mut Self::Property, AnimationEvaluationError> {
|
||||||
/// # >(
|
/// # let component = entity
|
||||||
/// # )))?
|
/// # .get_mut::<ExampleComponent>()
|
||||||
/// # .into_inner();
|
/// # .ok_or(AnimationEvaluationError::ComponentNotPresent(
|
||||||
/// # match component {
|
/// # TypeId::of::<ExampleComponent>()
|
||||||
/// # Projection::Perspective(perspective) => Ok(&mut perspective.fov),
|
/// # ))?
|
||||||
/// # _ => Err(AnimationEvaluationError::PropertyNotPresent(TypeId::of::<
|
/// # .into_inner();
|
||||||
/// # PerspectiveProjection,
|
/// # component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent(
|
||||||
/// # >(
|
/// # TypeId::of::<Option<f32>>()
|
||||||
/// # ))),
|
/// # ))
|
||||||
/// # }
|
/// # }
|
||||||
/// # }
|
/// # fn evaluator_id(&self) -> EvaluatorId {
|
||||||
/// # fn evaluator_id(&self) -> EvaluatorId {
|
/// # EvaluatorId::Type(TypeId::of::<Self>())
|
||||||
/// # EvaluatorId::Type(TypeId::of::<Self>())
|
/// # }
|
||||||
/// # }
|
|
||||||
/// # }
|
/// # }
|
||||||
/// let mut animation_clip = AnimationClip::default();
|
/// AnimatableCurve::new(
|
||||||
/// animation_clip.add_curve_to_target(
|
/// PowerLevelProperty,
|
||||||
/// animation_target_id,
|
/// AnimatableKeyframeCurve::new([
|
||||||
/// AnimatableCurve::new(
|
/// (0.0, 0.0),
|
||||||
/// FieldOfViewProperty,
|
/// (1.0, 9001.0),
|
||||||
/// AnimatableKeyframeCurve::new([
|
/// ]).expect("Failed to create power level curve")
|
||||||
/// (0.0, core::f32::consts::PI / 4.0),
|
|
||||||
/// (1.0, core::f32::consts::PI / 3.0),
|
|
||||||
/// ]).expect("Failed to create font size 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 {
|
pub trait AnimatableProperty: Send + Sync + 'static {
|
||||||
/// The animated property type.
|
/// The animated property type.
|
||||||
type Property: Animatable;
|
type Property: Animatable;
|
||||||
|
Loading…
Reference in New Issue
Block a user