fyrox_impl/scene/animation/
absm.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Animation blending state machine is a node that takes multiple animations from an animation player and
22//! mixes them in arbitrary way into one animation. See [`AnimationBlendingStateMachine`] docs for more info.
23
24use crate::scene::node::constructor::NodeConstructor;
25use crate::{
26    core::{
27        math::aabb::AxisAlignedBoundingBox,
28        pool::Handle,
29        reflect::prelude::*,
30        type_traits::prelude::*,
31        uuid::{uuid, Uuid},
32        variable::InheritableVariable,
33        visitor::prelude::*,
34    },
35    scene::{
36        animation::prelude::*,
37        base::{Base, BaseBuilder},
38        graph::Graph,
39        node::{Node, NodeTrait, UpdateContext},
40        Scene,
41    },
42};
43use fyrox_graph::constructor::ConstructorProvider;
44use fyrox_graph::{BaseSceneGraph, SceneGraph, SceneGraphNode};
45use std::ops::{Deref, DerefMut};
46
47/// Scene specific root motion settings.
48pub type RootMotionSettings = crate::generic_animation::RootMotionSettings<Handle<Node>>;
49/// Scene specific animation pose node.
50pub type PoseNode = crate::generic_animation::machine::PoseNode<Handle<Node>>;
51/// Scene specific animation pose node.
52pub type PlayAnimation = crate::generic_animation::machine::node::play::PlayAnimation<Handle<Node>>;
53/// Scene specific animation blending state machine BlendAnimations node.
54pub type BlendAnimations =
55    crate::generic_animation::machine::node::blend::BlendAnimations<Handle<Node>>;
56/// Scene specific animation blending state machine BlendAnimationsByIndex node.
57pub type BlendAnimationsByIndex =
58    crate::generic_animation::machine::node::blend::BlendAnimationsByIndex<Handle<Node>>;
59/// Scene specific animation blending state machine BlendPose node.
60pub type BlendPose = crate::generic_animation::machine::node::blend::BlendPose<Handle<Node>>;
61/// Scene specific animation blending state machine IndexedBlendInput node.
62pub type IndexedBlendInput =
63    crate::generic_animation::machine::node::blend::IndexedBlendInput<Handle<Node>>;
64/// Scene specific animation blending state machine BlendSpace node.
65pub type BlendSpace = crate::generic_animation::machine::node::blendspace::BlendSpace<Handle<Node>>;
66/// Scene specific animation blending state machine blend space point.
67pub type BlendSpacePoint =
68    crate::generic_animation::machine::node::blendspace::BlendSpacePoint<Handle<Node>>;
69/// Scene specific animation blending state machine layer mask.
70pub type LayerMask = crate::generic_animation::machine::mask::LayerMask<Handle<Node>>;
71/// Scene specific animation blending state machine layer mask.
72pub type Event = crate::generic_animation::machine::event::Event<Handle<Node>>;
73/// Scene specific animation blending state machine.
74pub type Machine = crate::generic_animation::machine::Machine<Handle<Node>>;
75/// Scene specific animation blending state machine layer.
76pub type MachineLayer = crate::generic_animation::machine::MachineLayer<Handle<Node>>;
77/// Scene specific animation blending state machine transition.
78pub type Transition = crate::generic_animation::machine::transition::Transition<Handle<Node>>;
79/// Scene specific animation blending state machine state.
80pub type State = crate::generic_animation::machine::state::State<Handle<Node>>;
81/// Scene specific animation blending state machine base pose node.
82pub type BasePoseNode = crate::generic_animation::machine::node::BasePoseNode<Handle<Node>>;
83/// Scene specific animation blending state machine state action.
84pub type StateAction = crate::generic_animation::machine::state::StateAction<Handle<Node>>;
85/// Scene specific animation blending state machine state action wrapper.
86pub type StateActionWrapper =
87    crate::generic_animation::machine::state::StateActionWrapper<Handle<Node>>;
88/// Scene specific animation blending state machine logic node.
89pub type LogicNode = crate::generic_animation::machine::transition::LogicNode<Handle<Node>>;
90/// Scene specific animation blending state machine And logic node.
91pub type AndNode = crate::generic_animation::machine::transition::AndNode<Handle<Node>>;
92/// Scene specific animation blending state machine Xor logic nde.
93pub type XorNode = crate::generic_animation::machine::transition::XorNode<Handle<Node>>;
94/// Scene specific animation blending state machine Or logic node.
95pub type OrNode = crate::generic_animation::machine::transition::OrNode<Handle<Node>>;
96/// Scene specific animation blending state machine Not logic node.
97pub type NotNode = crate::generic_animation::machine::transition::NotNode<Handle<Node>>;
98/// Scene specific animation blending state machine layer animation events collection.
99pub type LayerAnimationEventsCollection =
100    crate::generic_animation::machine::layer::LayerAnimationEventsCollection<Handle<Node>>;
101/// Scene specific animation blending state machine animation events source.
102pub type AnimationEventsSource =
103    crate::generic_animation::machine::layer::AnimationEventsSource<Handle<Node>>;
104
105/// Standard prelude for animation blending state machine, that contains all most commonly used types and traits.
106pub mod prelude {
107    pub use super::{
108        AndNode, AnimationBlendingStateMachine, AnimationBlendingStateMachineBuilder,
109        AnimationEventsSource, BasePoseNode, BlendAnimations, BlendAnimationsByIndex, BlendPose,
110        BlendSpace, BlendSpacePoint, Event, IndexedBlendInput, LayerAnimationEventsCollection,
111        LayerMask, LogicNode, Machine, MachineLayer, NotNode, OrNode, PlayAnimation, PoseNode,
112        RootMotionSettings, State, StateAction, StateActionWrapper, Transition, XorNode,
113    };
114    pub use crate::generic_animation::machine::{
115        node::AnimationEventCollectionStrategy,
116        parameter::{Parameter, ParameterContainer, ParameterDefinition, PoseWeight},
117    };
118}
119
120/// Extension trait for [`LayerMask`].
121pub trait LayerMaskExt {
122    /// Creates a layer mask for every descendant node starting from specified `root` (included). It could
123    /// be useful if you have an entire node hierarchy (for example, lower part of a body) that needs to
124    /// be filtered out.
125    fn from_hierarchy(graph: &Graph, root: Handle<Node>) -> Self;
126}
127
128impl LayerMaskExt for LayerMask {
129    fn from_hierarchy(graph: &Graph, root: Handle<Node>) -> Self {
130        Self::from(
131            graph
132                .traverse_iter(root)
133                .map(|(handle, _)| handle)
134                .collect::<Vec<_>>(),
135        )
136    }
137}
138
139/// Animation blending state machine (ABSM) is a node that takes multiple animations from an animation player and
140/// mixes them in arbitrary way into one animation. Usually, ABSMs are used to animate humanoid characters in games,
141/// by blending multiple states with one or more animations. More info about state machines can be found in
142/// [`Machine`] docs.
143///
144/// # Important notes
145///
146/// The node does **not** contain any animations, instead it just takes animations from an animation
147/// player node and mixes them.
148///
149/// # Example
150///
151/// You should always prefer using the editor (FyroxEd) to create animation blending state machines, for many cases
152/// creating machines by code is quite slow and hard to debug. The editor shows all the states, nodes, transitions and
153/// helps you to quickly debug your ABSMs. However, if you need to create a state machine from code (for example, for
154/// procedural animations), then the following example is for you.
155///
156/// ```rust
157/// # use fyrox_impl::{
158/// #     core::pool::Handle,
159/// #     scene::{
160/// #         animation::{absm::prelude::*, prelude::*},
161/// #         base::BaseBuilder,
162/// #         graph::Graph,
163/// #         node::Node,
164/// #     },
165/// # };
166/// # use fyrox_graph::SceneGraph;
167///
168/// fn create_walk_idle_state_machine(
169///     animation_player_handle: Handle<Node>,
170///     graph: &mut Graph,
171/// ) -> Handle<Node> {
172///     // Find idle and run animations first.
173///     let animation_player = graph
174///         .try_get_of_type::<AnimationPlayer>(animation_player_handle)
175///         .unwrap();
176///     let idle_animation = animation_player
177///         .animations()
178///         .find_by_name_ref("Idle")
179///         .unwrap()
180///         .0;
181///     let run_animation = animation_player
182///         .animations()
183///         .find_by_name_ref("Run")
184///         .unwrap()
185///         .0;
186///
187///     // Create state machine.
188///     let mut machine = Machine::new();
189///
190///     let root_layer = machine.layers_mut().first_mut().unwrap();
191///
192///     let idle_pose = root_layer.add_node(PoseNode::make_play_animation(idle_animation));
193///     let idle_state = root_layer.add_state(State::new("Idle", idle_pose));
194///
195///     let run_pose = root_layer.add_node(PoseNode::make_play_animation(run_animation));
196///     let run_state = root_layer.add_state(State::new("Idle", run_pose));
197///
198///     root_layer.add_transition(Transition::new(
199///         "Idle -> Run",
200///         idle_state,
201///         run_state,
202///         0.3,
203///         "Run",
204///     ));
205///     root_layer.add_transition(Transition::new(
206///         "Run -> Idle",
207///         idle_state,
208///         run_state,
209///         0.3,
210///         "Idle",
211///     ));
212///
213///     // Make the node.
214///     AnimationBlendingStateMachineBuilder::new(BaseBuilder::new())
215///         .with_machine(machine)
216///         .with_animation_player(animation_player_handle)
217///         .build(graph)
218/// }
219/// ```
220#[derive(Visit, Reflect, Clone, Debug, Default, ComponentProvider)]
221pub struct AnimationBlendingStateMachine {
222    base: Base,
223    #[component(include)]
224    machine: InheritableVariable<Machine>,
225    #[component(include)]
226    animation_player: InheritableVariable<Handle<Node>>,
227}
228
229impl AnimationBlendingStateMachine {
230    /// Sets new state machine to the node.
231    pub fn set_machine(&mut self, machine: Machine) {
232        self.machine.set_value_and_mark_modified(machine);
233    }
234
235    /// Returns a reference to the state machine used by the node.
236    pub fn machine(&self) -> &InheritableVariable<Machine> {
237        &self.machine
238    }
239
240    /// Returns a mutable reference to the state machine used by the node.
241    pub fn machine_mut(&mut self) -> &mut InheritableVariable<Machine> {
242        &mut self.machine
243    }
244
245    /// Sets new animation player of the node. The animation player is a source of animations for blending, the state
246    /// machine node must have the animation player specified, otherwise it won't have any effect.
247    pub fn set_animation_player(&mut self, animation_player: Handle<Node>) {
248        self.animation_player
249            .set_value_and_mark_modified(animation_player);
250    }
251
252    /// Returns an animation player used by the node.
253    pub fn animation_player(&self) -> Handle<Node> {
254        *self.animation_player
255    }
256}
257
258impl TypeUuidProvider for AnimationBlendingStateMachine {
259    fn type_uuid() -> Uuid {
260        uuid!("4b08c753-2a10-41e3-8fb2-4fd0517e86bc")
261    }
262}
263
264impl Deref for AnimationBlendingStateMachine {
265    type Target = Base;
266
267    fn deref(&self) -> &Self::Target {
268        &self.base
269    }
270}
271
272impl DerefMut for AnimationBlendingStateMachine {
273    fn deref_mut(&mut self) -> &mut Self::Target {
274        &mut self.base
275    }
276}
277
278impl ConstructorProvider<Node, Graph> for AnimationBlendingStateMachine {
279    fn constructor() -> NodeConstructor {
280        NodeConstructor::new::<Self>()
281            .with_variant("Animation Blending State Machine", |_| {
282                let mut machine = Machine::default();
283
284                let mut layer = MachineLayer::new();
285                layer.set_name("Base Layer");
286
287                machine.add_layer(layer);
288
289                AnimationBlendingStateMachineBuilder::new(
290                    BaseBuilder::new().with_name("Animation Blending State Machine"),
291                )
292                .with_machine(machine)
293                .build_node()
294                .into()
295            })
296            .with_group("Animation")
297    }
298}
299
300impl NodeTrait for AnimationBlendingStateMachine {
301    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
302        self.base.local_bounding_box()
303    }
304
305    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
306        self.base.world_bounding_box()
307    }
308
309    fn id(&self) -> Uuid {
310        Self::type_uuid()
311    }
312
313    fn update(&mut self, context: &mut UpdateContext) {
314        if let Some(animation_player) = context
315            .nodes
316            .try_borrow_mut(*self.animation_player)
317            .and_then(|n| n.component_mut::<AnimationPlayer>())
318        {
319            // Prevent animation player to apply animation to scene nodes. The animation will
320            // do than instead.
321            animation_player.set_auto_apply(false);
322
323            let pose = self.machine.get_value_mut_silent().evaluate_pose(
324                animation_player.animations.get_value_mut_silent(),
325                context.dt,
326            );
327
328            pose.apply_internal(context.nodes);
329        }
330    }
331
332    fn validate(&self, scene: &Scene) -> Result<(), String> {
333        if scene
334            .graph
335            .try_get(*self.animation_player)
336            .and_then(|n| n.component_ref::<AnimationPlayer>())
337            .is_none()
338        {
339            Err(
340                "Animation player is not set or invalid! Animation blending state \
341            machine won't operate! Set the animation player handle in the Inspector."
342                    .to_string(),
343            )
344        } else {
345            Ok(())
346        }
347    }
348}
349
350/// Animation blending state machine builder allows you to create state machines in declarative manner.
351pub struct AnimationBlendingStateMachineBuilder {
352    base_builder: BaseBuilder,
353    machine: Machine,
354    animation_player: Handle<Node>,
355}
356
357impl AnimationBlendingStateMachineBuilder {
358    /// Creates new builder instance.
359    pub fn new(base_builder: BaseBuilder) -> Self {
360        Self {
361            base_builder,
362            machine: Default::default(),
363            animation_player: Default::default(),
364        }
365    }
366
367    /// Sets the desired state machine.
368    pub fn with_machine(mut self, machine: Machine) -> Self {
369        self.machine = machine;
370        self
371    }
372
373    /// Sets the animation player as a source of animations.
374    pub fn with_animation_player(mut self, animation_player: Handle<Node>) -> Self {
375        self.animation_player = animation_player;
376        self
377    }
378
379    /// Creates new node.
380    pub fn build_node(self) -> Node {
381        Node::new(AnimationBlendingStateMachine {
382            base: self.base_builder.build_base(),
383            machine: self.machine.into(),
384            animation_player: self.animation_player.into(),
385        })
386    }
387
388    /// Creates new node and adds it to the graph.
389    pub fn build(self, graph: &mut Graph) -> Handle<Node> {
390        graph.add_node(self.build_node())
391    }
392}