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.
199 lines
8.6 KiB
C#
199 lines
8.6 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
namespace Pegasus
|
|
{
|
|
/// <summary>
|
|
/// This class can be attached to Mecanim based objects to change the animation state based on the speed at which the object is travelling.
|
|
/// </summary>
|
|
public class PegasusAnimator : MonoBehaviour
|
|
{
|
|
//Whats being controlled, and current state
|
|
[Header("Character And Animator")]
|
|
[Tooltip("Drop your character here. By default it will select the character this script is attached to.")]
|
|
public Transform m_character;
|
|
[Tooltip("Drop your animator here. By default it will select the animator on the character this script is attached to.")]
|
|
public Animator m_animator;
|
|
[Tooltip("Select your initial animation state. This will be played immediately on start at runtime.")]
|
|
public PegasusConstants.PegasusAnimationState m_animationState = PegasusConstants.PegasusAnimationState.Idle;
|
|
//private PegasusConstants.PegasusAnimationState m_lastAnimationState = PegasusConstants.PegasusAnimationState.Idle;
|
|
|
|
//Override the animations that get played - changed only at the start of the playback
|
|
[Header("Optional Animation Overrides")]
|
|
[Tooltip("Add your idle animation override here. This is optional, and the default animation will be used instead if not supplied.")]
|
|
public AnimationClip m_idleAnimation;
|
|
[Tooltip("Add your walk animation override here. This is optional, and the default animation will be used instead if not supplied.")]
|
|
public AnimationClip m_walkAnimation;
|
|
[Tooltip("Add your run animation override here. This is optional, and the default animation will be used instead if not supplied.")]
|
|
public AnimationClip m_runAnimation;
|
|
|
|
//Typical idle, walk & run speeds - override to influence animation speeds
|
|
[Header("Walk & Run Speeds (m/sec)")]
|
|
[Tooltip("Walk animations will play when the character movement is greater than the idle speed and less than this speed.")]
|
|
public float m_walkSpeed = 2f;
|
|
[Tooltip("Walk animations will play when the character movement is greater than the idle speed and less than this speed.")]
|
|
public float m_maxWalkSpeed = 3.5f;
|
|
[Tooltip("Run animations will play when the character movement is greater than the walk speed.")]
|
|
public float m_runSpeed = 7f;
|
|
|
|
//Internal variables
|
|
private float m_speedDamping = 0.7f;
|
|
private float m_speed = 0f;
|
|
private float m_lastSpeed = float.MinValue;
|
|
private Vector3 m_lastPosition = Vector3.zero;
|
|
private float m_animationMultiplier = 1f;
|
|
private int m_animationStateHash = Animator.StringToHash("AnimationState");
|
|
private int m_animationMultiplierHash = Animator.StringToHash("AnimationMultiplier");
|
|
|
|
void Start()
|
|
{
|
|
if (m_character == null)
|
|
{
|
|
m_character = gameObject.transform;
|
|
}
|
|
|
|
if (m_animator == null)
|
|
{
|
|
m_animator = GetComponent<Animator>();
|
|
}
|
|
|
|
if (m_animator != null)
|
|
{
|
|
m_lastPosition = transform.position;
|
|
|
|
if (m_idleAnimation != null)
|
|
{
|
|
ReplaceClip(m_animator, "HumanoidIdle", m_idleAnimation);
|
|
}
|
|
if (m_walkAnimation != null)
|
|
{
|
|
ReplaceClip(m_animator, "HumanoidWalk", m_walkAnimation);
|
|
}
|
|
if (m_runAnimation != null)
|
|
{
|
|
ReplaceClip(m_animator, "HumanoidRun", m_runAnimation);
|
|
}
|
|
|
|
PlayState(m_animationState, true);
|
|
}
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
//Exit if we are not connected to anything
|
|
if (m_animator == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float distance = Vector3.Distance(transform.position, m_lastPosition);
|
|
m_lastPosition = transform.position;
|
|
|
|
if (Time.deltaTime > 0f)
|
|
{
|
|
//Get damped speed - damping smooths out frame rate variations a little
|
|
m_speed = Mathf.Lerp(m_speed, distance / Time.deltaTime, Time.deltaTime * (1f / m_speedDamping));
|
|
|
|
//Determine what state we should be in, and adjust animation multiplier
|
|
if (m_speed > m_maxWalkSpeed)
|
|
{
|
|
m_animationState = PegasusConstants.PegasusAnimationState.Running;
|
|
m_animationMultiplier = m_speed / m_runSpeed;
|
|
}
|
|
else if (m_speed > 0f)
|
|
{
|
|
m_animationState = PegasusConstants.PegasusAnimationState.Walking;
|
|
m_animationMultiplier = m_speed / m_walkSpeed;
|
|
}
|
|
else
|
|
{
|
|
m_animationState = PegasusConstants.PegasusAnimationState.Idle;
|
|
m_animationMultiplier = 1f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_speed = 0f;
|
|
m_animationState = PegasusConstants.PegasusAnimationState.Idle;
|
|
m_animationMultiplier = 1f;
|
|
}
|
|
|
|
if (m_animator != null && m_speed != m_lastSpeed)
|
|
{
|
|
m_lastSpeed = m_speed;
|
|
m_animator.SetInteger(m_animationStateHash, (int)m_animationState);
|
|
m_animator.SetFloat(m_animationMultiplierHash, m_animationMultiplier);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Play an animation state
|
|
/// </summary>
|
|
/// <param name="newState">The new state</param>
|
|
/// <param name="forceStateNow">Force an animation state update</param>
|
|
private void PlayState(PegasusConstants.PegasusAnimationState newState, bool forceStateNow)
|
|
{
|
|
if (forceStateNow)
|
|
{
|
|
//Set variables
|
|
m_animationState = newState;
|
|
m_animator.SetInteger(m_animationStateHash, (int)m_animationState);
|
|
|
|
//Force animation
|
|
switch (m_animationState)
|
|
{
|
|
case PegasusConstants.PegasusAnimationState.Idle:
|
|
m_animator.Play("Base Layer.Idle");
|
|
break;
|
|
case PegasusConstants.PegasusAnimationState.Walking:
|
|
m_animator.Play("Base Layer.Walk");
|
|
break;
|
|
case PegasusConstants.PegasusAnimationState.Running:
|
|
m_animator.Play("Base Layer.Run");
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
else if (m_animationState != newState)
|
|
{
|
|
//Set variables
|
|
m_animationState = newState;
|
|
m_animator.SetInteger(m_animationStateHash, (int)m_animationState);
|
|
}
|
|
|
|
//And update the animation speed multiplier
|
|
m_animator.SetFloat(m_animationMultiplierHash, m_animationMultiplier);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Replace a clip with another one
|
|
/// </summary>
|
|
/// <param name="animator">Animator its being replaced on</param>
|
|
/// <param name="clipName">Clip name</param>
|
|
/// <param name="overrideClip">New clip</param>
|
|
private void ReplaceClip(Animator animator, string clipName, AnimationClip overrideClip)
|
|
{
|
|
AnimatorOverrideController overrideController = animator.runtimeAnimatorController as AnimatorOverrideController;
|
|
if (overrideController == null)
|
|
{
|
|
overrideController = new AnimatorOverrideController();
|
|
overrideController.name = "PegasusRuntimeController";
|
|
overrideController.runtimeAnimatorController = animator.runtimeAnimatorController;
|
|
}
|
|
overrideController[clipName] = overrideClip;
|
|
if (ReferenceEquals(animator.runtimeAnimatorController, overrideController) == false)
|
|
{
|
|
animator.runtimeAnimatorController = overrideController;
|
|
}
|
|
}
|
|
|
|
// #if UNITY_EDITOR
|
|
// var settings = AnimationUtility.GetAnimationClipSettings(m_idleAnimation);
|
|
// settings.loopTime = m_loopIdleAnimation;
|
|
// settings.loopBlend = m_loopIdleAnimation;
|
|
// AnimationUtility.SetAnimationClipSettings(m_idleAnimation, settings);
|
|
// #endif
|
|
}
|
|
} |