// Animancer // Copyright 2020 Kybernetik //
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
using System;
using UnityEngine;
namespace Animancer.Examples.Locomotion
{
///
/// Demonstrates how to use Root Motion for some animations but not others.
///
[AddComponentMenu(Strings.MenuPrefix + "Examples/Locomotion - Root Motion")]
[HelpURL(Strings.APIDocumentationURL + ".Examples.Locomotion/RootMotion")]
public sealed class RootMotion : MonoBehaviour
{
/************************************************************************************************************************/
///
/// A with an toggle.
///
[Serializable]
public class MotionTransition : ClipState.Transition
{
/************************************************************************************************************************/
[SerializeField, Tooltip("Determines if Root Motion should be enabled when this animation plays")]
private bool _ApplyRootMotion;
/************************************************************************************************************************/
public override void Apply(AnimancerState state)
{
base.Apply(state);
state.Root.Component.Animator.applyRootMotion = _ApplyRootMotion;
}
/************************************************************************************************************************/
}
/************************************************************************************************************************/
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private float _MaxDistance;
[SerializeField] private MotionTransition[] _Animations;
private Vector3 _Start;
/************************************************************************************************************************/
private void OnEnable()
{
_Start = transform.position;
Play(0);
}
/************************************************************************************************************************/
/// Plays the animation at the specified `index` in the array.
/// This method is called by UI Buttons.
public void Play(int index)
{
_Animancer.Play(_Animations[index]);
}
/************************************************************************************************************************/
///
/// Teleports this object back to its starting location if it moves too far.
///
private void FixedUpdate()
{
if (Vector3.Distance(_Start, transform.position) > _MaxDistance)
transform.position = _Start;
}
/************************************************************************************************************************/
// These fields determine which object the Root Motion will be applied to.
// You would normally only have one of these for whichever system you are using to move your characters.
// But for this example, we have all of them to demonstrate how each could be used.
[SerializeField] private Transform _MotionTransform;
[SerializeField] private Rigidbody _MotionRigidbody;
[SerializeField] private CharacterController _MotionCharacterController;
///
/// Called when the would apply Root Motion. Applies that Root Motion to a different
/// object instead.
///
/// This can be useful if for example the character's or
/// is on a parent of the so that the model is kept
/// separate from the character's mechanics.
///
private void OnAnimatorMove()
{
if (!_Animancer.Animator.applyRootMotion)
return;
if (_MotionTransform != null)
{
_MotionTransform.position += _Animancer.Animator.deltaPosition;
_MotionTransform.rotation *= _Animancer.Animator.deltaRotation;
}
else if (_MotionRigidbody != null)
{
_MotionRigidbody.MovePosition(_MotionRigidbody.position + _Animancer.Animator.deltaPosition);
_MotionRigidbody.MoveRotation(_MotionRigidbody.rotation * _Animancer.Animator.deltaRotation);
}
else if (_MotionCharacterController != null)
{
_MotionCharacterController.Move(_Animancer.Animator.deltaPosition);
_MotionCharacterController.transform.rotation *= _Animancer.Animator.deltaRotation;
}
else
{
// If we aren't retargeting, just let Unity apply the Root Motion normally.
_Animancer.Animator.ApplyBuiltinRootMotion();
}
}
/************************************************************************************************************************/
}
}