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::SceneGraph;
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<AnimationPlayer>,
170/// graph: &mut Graph,
171/// ) -> Handle<AnimationBlendingStateMachine> {
172/// // Find idle and run animations first.
173/// let animation_player = graph
174/// .try_get(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)]
221#[reflect(derived_type = "Node")]
222pub struct AnimationBlendingStateMachine {
223 base: Base,
224 #[component(include)]
225 machine: InheritableVariable<Machine>,
226 #[component(include)]
227 animation_player: InheritableVariable<Handle<AnimationPlayer>>,
228}
229
230impl AnimationBlendingStateMachine {
231 /// Sets new state machine to the node.
232 pub fn set_machine(&mut self, machine: Machine) {
233 self.machine.set_value_and_mark_modified(machine);
234 }
235
236 /// Returns a reference to the state machine used by the node.
237 pub fn machine(&self) -> &InheritableVariable<Machine> {
238 &self.machine
239 }
240
241 /// Returns a mutable reference to the state machine used by the node.
242 pub fn machine_mut(&mut self) -> &mut InheritableVariable<Machine> {
243 &mut self.machine
244 }
245
246 /// Sets new animation player of the node. The animation player is a source of animations for blending, the state
247 /// machine node must have the animation player specified, otherwise it won't have any effect.
248 pub fn set_animation_player(&mut self, animation_player: Handle<AnimationPlayer>) {
249 self.animation_player
250 .set_value_and_mark_modified(animation_player);
251 }
252
253 /// Returns an animation player used by the node.
254 pub fn animation_player(&self) -> Handle<AnimationPlayer> {
255 *self.animation_player
256 }
257}
258
259impl TypeUuidProvider for AnimationBlendingStateMachine {
260 fn type_uuid() -> Uuid {
261 uuid!("4b08c753-2a10-41e3-8fb2-4fd0517e86bc")
262 }
263}
264
265impl Deref for AnimationBlendingStateMachine {
266 type Target = Base;
267
268 fn deref(&self) -> &Self::Target {
269 &self.base
270 }
271}
272
273impl DerefMut for AnimationBlendingStateMachine {
274 fn deref_mut(&mut self) -> &mut Self::Target {
275 &mut self.base
276 }
277}
278
279impl ConstructorProvider<Node, Graph> for AnimationBlendingStateMachine {
280 fn constructor() -> NodeConstructor {
281 NodeConstructor::new::<Self>()
282 .with_variant("Animation Blending State Machine", |_| {
283 let mut machine = Machine::default();
284
285 let mut layer = MachineLayer::new();
286 layer.set_name("Base Layer");
287
288 machine.add_layer(layer);
289
290 AnimationBlendingStateMachineBuilder::new(
291 BaseBuilder::new().with_name("Animation Blending State Machine"),
292 )
293 .with_machine(machine)
294 .build_node()
295 .into()
296 })
297 .with_group("Animation")
298 }
299}
300
301impl NodeTrait for AnimationBlendingStateMachine {
302 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
303 self.base.local_bounding_box()
304 }
305
306 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
307 self.base.world_bounding_box()
308 }
309
310 fn id(&self) -> Uuid {
311 Self::type_uuid()
312 }
313
314 fn update(&mut self, context: &mut UpdateContext) {
315 if let Ok(animation_player) = context.nodes.try_get_mut(*self.animation_player) {
316 // Prevent animation player to apply animation to scene nodes. The animation will
317 // do than instead.
318 animation_player.set_auto_apply(false);
319
320 let pose = self.machine.get_value_mut_silent().evaluate_pose(
321 animation_player.animations.get_value_mut_silent(),
322 context.dt,
323 );
324
325 pose.apply_internal(context.nodes);
326 }
327 }
328
329 fn validate(&self, scene: &Scene) -> Result<(), String> {
330 if scene.graph.try_get(*self.animation_player).is_err() {
331 Err(
332 "Animation player is not set or invalid! Animation blending state \
333 machine won't operate! Set the animation player handle in the Inspector."
334 .to_string(),
335 )
336 } else {
337 Ok(())
338 }
339 }
340}
341
342/// Animation blending state machine builder allows you to create state machines in declarative manner.
343pub struct AnimationBlendingStateMachineBuilder {
344 base_builder: BaseBuilder,
345 machine: Machine,
346 animation_player: Handle<AnimationPlayer>,
347}
348
349impl AnimationBlendingStateMachineBuilder {
350 /// Creates new builder instance.
351 pub fn new(base_builder: BaseBuilder) -> Self {
352 Self {
353 base_builder,
354 machine: Default::default(),
355 animation_player: Default::default(),
356 }
357 }
358
359 /// Sets the desired state machine.
360 pub fn with_machine(mut self, machine: Machine) -> Self {
361 self.machine = machine;
362 self
363 }
364
365 /// Sets the animation player as a source of animations.
366 pub fn with_animation_player(mut self, animation_player: Handle<AnimationPlayer>) -> Self {
367 self.animation_player = animation_player;
368 self
369 }
370
371 /// Creates new node.
372 pub fn build_node(self) -> Node {
373 Node::new(AnimationBlendingStateMachine {
374 base: self.base_builder.build_base(),
375 machine: self.machine.into(),
376 animation_player: self.animation_player.into(),
377 })
378 }
379
380 /// Creates new node and adds it to the graph.
381 pub fn build(self, graph: &mut Graph) -> Handle<AnimationBlendingStateMachine> {
382 graph.add_node(self.build_node()).to_variant()
383 }
384}