You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
5.4 KiB
C#
124 lines
5.4 KiB
C#
// 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
|
|
{
|
|
/// <summary>
|
|
/// Demonstrates how to use Root Motion for some animations but not others.
|
|
/// </summary>
|
|
[AddComponentMenu(Strings.MenuPrefix + "Examples/Locomotion - Root Motion")]
|
|
[HelpURL(Strings.APIDocumentationURL + ".Examples.Locomotion/RootMotion")]
|
|
public sealed class RootMotion : MonoBehaviour
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>
|
|
/// A <see cref="ClipState.Transition"/> with an <see cref="_ApplyRootMotion"/> toggle.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Plays the animation at the specified `index` in the <see cref="_Animations"/> array.</summary>
|
|
/// <remarks>This method is called by UI Buttons.</remarks>
|
|
public void Play(int index)
|
|
{
|
|
_Animancer.Play(_Animations[index]);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>
|
|
/// Teleports this object back to its starting location if it moves too far.
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// Called when the <see cref="Animator"/> would apply Root Motion. Applies that Root Motion to a different
|
|
/// object instead.
|
|
/// <para></para>
|
|
/// This can be useful if for example the character's <see cref="Rigidbody"/> or
|
|
/// <see cref="CharacterController"/> is on a parent of the <see cref="Animator"/> so that the model is kept
|
|
/// separate from the character's mechanics.
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|