fyrox_impl/scene/animation/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
//! Animation player is a node that contains multiple animations. It updates and plays all the animations.
//! See [`AnimationPlayer`] docs for more info.
use crate::{
core::{
log::{Log, MessageKind},
math::aabb::AxisAlignedBoundingBox,
pool::Handle,
reflect::prelude::*,
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
generic_animation::value::{BoundValueCollection, TrackValue, ValueBinding},
scene::{
base::{Base, BaseBuilder},
graph::{Graph, NodePool},
node::{Node, NodeTrait, UpdateContext},
},
};
use fyrox_graph::BaseSceneGraph;
use std::ops::{Deref, DerefMut};
pub mod absm;
pub mod spritesheet;
/// Scene specific animation.
pub type Animation = crate::generic_animation::Animation<Handle<Node>>;
/// Scene specific animation track.
pub type Track = crate::generic_animation::track::Track<Handle<Node>>;
/// Scene specific animation container.
pub type AnimationContainer = crate::generic_animation::AnimationContainer<Handle<Node>>;
/// Scene specific animation pose.
pub type AnimationPose = crate::generic_animation::AnimationPose<Handle<Node>>;
/// Scene specific animation node pose.
pub type NodePose = crate::generic_animation::NodePose<Handle<Node>>;
/// Standard prelude for animations, that contains all most commonly used types and traits.
pub mod prelude {
pub use super::{
Animation, AnimationContainer, AnimationContainerExt, AnimationPlayer,
AnimationPlayerBuilder, AnimationPose, AnimationPoseExt, BoundValueCollectionExt, NodePose,
Track,
};
pub use crate::generic_animation::{
container::{TrackDataContainer, TrackValueKind},
signal::AnimationSignal,
value::{BoundValueCollection, TrackValue, ValueBinding, ValueType},
AnimationEvent,
};
}
/// Extension trait for [`AnimationContainer`].
pub trait AnimationContainerExt {
/// Updates all animations in the container and applies their poses to respective nodes. This method is intended to
/// be used only by the internals of the engine!
fn update_animations(&mut self, nodes: &mut NodePool, apply: bool, dt: f32);
}
impl AnimationContainerExt for AnimationContainer {
fn update_animations(&mut self, nodes: &mut NodePool, apply: bool, dt: f32) {
for animation in self.iter_mut().filter(|anim| anim.is_enabled()) {
animation.tick(dt);
if apply {
animation.pose().apply_internal(nodes);
}
}
}
}
/// Extension trait for [`AnimationPose`].
pub trait AnimationPoseExt {
/// Tries to set each value to the each property from the animation pose to respective scene nodes.
fn apply_internal(&self, nodes: &mut NodePool);
/// Tries to set each value to the each property from the animation pose to respective scene nodes.
fn apply(&self, graph: &mut Graph);
/// Calls given callback function for each node and allows you to apply pose with your own
/// rules. This could be useful if you need to ignore transform some part of pose for a node.
fn apply_with<C>(&self, graph: &mut Graph, callback: C)
where
C: FnMut(&mut Node, Handle<Node>, &NodePose);
}
impl AnimationPoseExt for AnimationPose {
fn apply_internal(&self, nodes: &mut NodePool) {
for (node, local_pose) in self.poses() {
if node.is_none() {
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
} else if let Some(node) = nodes.try_borrow_mut(*node) {
local_pose.values.apply(node);
}
}
}
fn apply(&self, graph: &mut Graph) {
for (node, local_pose) in self.poses() {
if node.is_none() {
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
} else if let Some(node) = graph.try_get_mut(*node) {
local_pose.values.apply(node);
}
}
}
fn apply_with<C>(&self, graph: &mut Graph, mut callback: C)
where
C: FnMut(&mut Node, Handle<Node>, &NodePose),
{
for (node, local_pose) in self.poses() {
if node.is_none() {
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
} else if let Some(node_ref) = graph.try_get_mut(*node) {
callback(node_ref, *node, local_pose);
}
}
}
}
/// Extension trait for [`BoundValueCollection`].
pub trait BoundValueCollectionExt {
/// Tries to set each value from the collection to the respective property (by binding) of the given scene node.
fn apply(&self, node_ref: &mut Node);
}
impl BoundValueCollectionExt for BoundValueCollection {
fn apply(&self, node_ref: &mut Node) {
for bound_value in self.values.iter() {
match bound_value.binding {
ValueBinding::Position => {
if let TrackValue::Vector3(v) = bound_value.value {
node_ref.local_transform_mut().set_position(v);
} else {
Log::err(
"Unable to apply position, because underlying type is not Vector3!",
)
}
}
ValueBinding::Scale => {
if let TrackValue::Vector3(v) = bound_value.value {
node_ref.local_transform_mut().set_scale(v);
} else {
Log::err("Unable to apply scaling, because underlying type is not Vector3!")
}
}
ValueBinding::Rotation => {
if let TrackValue::UnitQuaternion(v) = bound_value.value {
node_ref.local_transform_mut().set_rotation(v);
} else {
Log::err("Unable to apply rotation, because underlying type is not UnitQuaternion!")
}
}
ValueBinding::Property {
name: ref property_name,
value_type,
} => bound_value.apply_to_object(node_ref, property_name, value_type),
}
}
}
}
/// Animation player is a node that contains multiple animations. It updates and plays all the animations.
/// The node could be a source of animations for animation blending state machines. To learn more about
/// animations, see [`Animation`] docs.
///
/// # Examples
///
/// Always prefer using animation editor to create animation player nodes. It has rich functionality and
/// an ability to preview the result of animations. If you need to create an animation procedurally, the
/// next code snippet is for you.
///
/// ```rust
/// # use fyrox_impl::{
/// # core::{
/// # math::curve::{Curve, CurveKey, CurveKeyKind},
/// # pool::Handle,
/// # },
/// # scene::{animation::prelude::*, base::BaseBuilder, graph::Graph, node::Node},
/// # };
///
/// fn create_bounce_animation(animated_node: Handle<Node>) -> Animation {
/// let mut frames_container = TrackDataContainer::new(TrackValueKind::Vector3);
///
/// // We'll animate only Y coordinate (at index 1).
/// frames_container.curves_mut()[1] = Curve::from(vec![
/// CurveKey::new(0.1, 1.0, CurveKeyKind::Linear),
/// CurveKey::new(0.2, 0.0, CurveKeyKind::Linear),
/// CurveKey::new(0.3, 0.75, CurveKeyKind::Linear),
/// CurveKey::new(0.4, 0.0, CurveKeyKind::Linear),
/// CurveKey::new(0.5, 0.25, CurveKeyKind::Linear),
/// CurveKey::new(0.6, 0.0, CurveKeyKind::Linear),
/// ]);
///
/// // Create a track that will animated the node using the curve above.
/// let mut track = Track::new(frames_container, ValueBinding::Position);
/// track.set_target(animated_node);
///
/// // Finally create an animation and set its time slice and turn it on.
/// let mut animation = Animation::default();
/// animation.add_track(track);
/// animation.set_time_slice(0.0..0.6);
/// animation.set_enabled(true);
/// animation
/// }
///
/// fn create_bounce_animation_player(
/// animated_node: Handle<Node>,
/// graph: &mut Graph,
/// ) -> Handle<Node> {
/// let mut animations = AnimationContainer::new();
///
/// // Create a bounce animation.
/// animations.add(create_bounce_animation(animated_node));
///
/// AnimationPlayerBuilder::new(BaseBuilder::new())
/// .with_animations(animations)
/// .build(graph)
/// }
/// ```
///
/// As you can see, the example is quite big. That's why you should always prefer using the editor to create animations.
/// The example creates a bounce animation first - it is a simple animation that animates position of a given node
/// (`animated_node`). Only then it creates an animation player node with an animation container with a single animation.
/// To understand why this is so complicated, see the docs of [`Animation`].
#[derive(Visit, Reflect, Clone, Debug)]
pub struct AnimationPlayer {
base: Base,
animations: InheritableVariable<AnimationContainer>,
auto_apply: bool,
}
impl Default for AnimationPlayer {
fn default() -> Self {
Self {
base: Default::default(),
animations: Default::default(),
auto_apply: true,
}
}
}
impl AnimationPlayer {
/// Enables or disables automatic animation pose applying. Every animation in the node is updated first, and
/// then their output pose could be applied to the graph, so the animation takes effect. Automatic applying
/// is useful when you need your animations to be applied immediately to the graph, but in some cases (if you're
/// using animation blending state machines for example) this functionality is undesired.
pub fn set_auto_apply(&mut self, auto_apply: bool) {
self.auto_apply = auto_apply;
}
/// Returns `true` if the node is automatically applying output poses of animations to the graph, `false` -
/// otherwise.
pub fn is_auto_apply(&self) -> bool {
self.auto_apply
}
/// Returns a reference to internal animations container.
pub fn animations(&self) -> &InheritableVariable<AnimationContainer> {
&self.animations
}
/// Returns a reference to internal animations container. Keep in mind that mutable access to [`InheritableVariable`]
/// may have side effects if used inappropriately. Checks docs for [`InheritableVariable`] for more info.
pub fn animations_mut(&mut self) -> &mut InheritableVariable<AnimationContainer> {
&mut self.animations
}
/// Sets new animations container of the animation player.
pub fn set_animations(&mut self, animations: AnimationContainer) {
self.animations.set_value_and_mark_modified(animations);
}
}
impl TypeUuidProvider for AnimationPlayer {
fn type_uuid() -> Uuid {
uuid!("44d1c94e-354f-4f9a-b918-9d31c28aa16a")
}
}
impl Deref for AnimationPlayer {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for AnimationPlayer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl NodeTrait for AnimationPlayer {
crate::impl_query_component!(
animations: InheritableVariable<AnimationContainer>,
auto_apply: bool
);
fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
self.base.local_bounding_box()
}
fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
self.base.world_bounding_box()
}
fn id(&self) -> Uuid {
Self::type_uuid()
}
fn update(&mut self, context: &mut UpdateContext) {
self.animations.get_value_mut_silent().update_animations(
context.nodes,
self.auto_apply,
context.dt,
);
}
}
/// A builder for [`AnimationPlayer`] node.
pub struct AnimationPlayerBuilder {
base_builder: BaseBuilder,
animations: AnimationContainer,
auto_apply: bool,
}
impl AnimationPlayerBuilder {
/// Creates new builder instance.
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
animations: AnimationContainer::new(),
auto_apply: true,
}
}
/// Sets a container with desired animations.
pub fn with_animations(mut self, animations: AnimationContainer) -> Self {
self.animations = animations;
self
}
/// Enables or disables automatic pose applying. See [`AnimationPlayer::set_auto_apply`] docs for more info.
pub fn with_auto_apply(mut self, auto_apply: bool) -> Self {
self.auto_apply = auto_apply;
self
}
/// Creates an instance of [`AnimationPlayer`] node.
pub fn build_node(self) -> Node {
Node::new(AnimationPlayer {
base: self.base_builder.build_base(),
animations: self.animations.into(),
auto_apply: self.auto_apply,
})
}
/// Creates an instance of [`AnimationPlayer`] node and adds it to the given scene graph.
pub fn build(self, graph: &mut Graph) -> Handle<Node> {
graph.add_node(self.build_node())
}
}