wde_animation/lib.rs
1//! Rigid-part animation for WaterDropEngine.
2//!
3//! A model is animated by moving rigid parts: each part hangs under an [`AnimationBone`] entity,
4//! whose transform is driven by an [`AnimationClip`] (one keyframe track per bone name). An
5//! [`AnimationPlayer`] on the root of the hierarchy plays and crossfades clips onto every bone
6//! below it.
7//!
8//! # Example
9//! glTF models with `%B%<bone>` nodes spawn their bones automatically, and expose their clips:
10//! ```rust
11//! fn walk(mut players: Query<&mut AnimationPlayer>, gltf: Res<Assets<GltfAsset>>, model: Res<Model>) {
12//! let walk = gltf.get(&model.0).unwrap().animation("Walk").unwrap();
13//! for mut player in &mut players {
14//! player.crossfade(walk.clone(), 0.2).set_speed(1.5);
15//! }
16//! }
17//! ```
18
19use bevy::prelude::*;
20
21mod clip;
22mod player;
23
24pub use clip::{AnimationClip, BoneTrack, Interpolation, Keyframes};
25pub use player::{AnimationBone, AnimationPlayer};
26
27#[doc(hidden)]
28pub mod prelude {
29 pub use crate::{AnimationBone, AnimationClip, AnimationPlayer, AnimationSystems};
30}
31
32/// Systems advancing the players and posing the bones, in [`Update`].
33#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
34pub struct AnimationSystems;
35
36pub struct AnimationPlugin;
37impl Plugin for AnimationPlugin {
38 fn build(&self, app: &mut App) {
39 app.init_asset::<AnimationClip>().add_systems(
40 Update,
41 (
42 player::link_bones,
43 player::advance_players,
44 player::pose_bones
45 )
46 .chain()
47 .in_set(AnimationSystems)
48 );
49 }
50}