Skip to main content

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}