// Animancer // Copyright 2020 Kybernetik //
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using Object = UnityEngine.Object;
namespace Animancer
{
///
/// An which uses the s of s
/// so they can be referenced using strings as well as the clips themselves.
///
/// It also has fields to automatically register animations on startup and play the first one automatically without
/// needing another script to control it, much like Unity's Legacy component.
///
[AddComponentMenu(Strings.MenuPrefix + "Named Animancer Component")]
[HelpURL(Strings.APIDocumentationURL + "/NamedAnimancerComponent")]
public class NamedAnimancerComponent : AnimancerComponent
{
/************************************************************************************************************************/
#region Fields and Properties
/************************************************************************************************************************/
[SerializeField, Tooltip("If true, the 'Default Animation' will be automatically played by OnEnable")]
private bool _PlayAutomatically = true;
/// []
/// If true, the first clip in the array will be automatically played by
/// .
///
public bool PlayAutomatically
{
get { return _PlayAutomatically; }
set { _PlayAutomatically = value; }
}
/************************************************************************************************************************/
[SerializeField, Tooltip("Animations in this array will be automatically registered by Awake" +
" as states that can be retrieved using their name")]
private AnimationClip[] _Animations;
/// []
/// Animations in this array will be automatically registered by as states that can be
/// retrieved using their name and the first element will be played by if
/// is true.
///
public AnimationClip[] Animations
{
get { return _Animations; }
set
{
_Animations = value;
if (value != null && value.Length > 0)
States.CreateIfNew(value);
}
}
/************************************************************************************************************************/
///
/// The first element in the array. It will be automatically played by
/// if is true.
///
public AnimationClip DefaultAnimation
{
get
{
if (_Animations == null || _Animations.Length == 0)
return null;
else
return _Animations[0];
}
set
{
if (_Animations == null || _Animations.Length == 0)
_Animations = new AnimationClip[] { value };
else
_Animations[0] = value;
}
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
#region Initialisation
/************************************************************************************************************************/
#if UNITY_EDITOR
/// [Editor-Only]
/// Called by the Unity Editor in Edit Mode whenever an instance of this script is loaded or a value is changed
/// in the Inspector.
///
/// Uses to ensure that all of the clips in the
/// array are supported by the system and removes any others.
///
protected virtual void OnValidate()
{
if (_Animations == null)
return;
for (int i = 0; i < _Animations.Length; i++)
{
var clip = _Animations[i];
if (clip == null)
continue;
try
{
Validate.NotLegacy(clip);
continue;
}
catch (Exception ex)
{
Debug.LogException(ex, clip);
}
Array.Copy(_Animations, i + 1, _Animations, i, _Animations.Length - (i + 1));
Array.Resize(ref _Animations, _Animations.Length - 1);
i--;
}
}
#endif
/************************************************************************************************************************/
///
/// Called by Unity when this component is being loaded.
///
/// Creates a state for each clip in the array.
///
protected virtual void Awake()
{
if (_Animations != null && _Animations.Length > 0)
States.CreateIfNew(_Animations);
}
/************************************************************************************************************************/
///
/// Called by Unity when this component becomes enabled and active.
///
/// Plays the first clip in the array if is true.
///
/// Plays the if it was stopped.
///
protected override void OnEnable()
{
base.OnEnable();
if (_PlayAutomatically && _Animations != null && _Animations.Length > 0)
{
var clip = _Animations[0];
if (clip != null)
Play(clip);
}
}
/************************************************************************************************************************/
/// []
/// Gathers all the animations in the and the array.
///
public override void GatherAnimationClips(ICollection clips)
{
base.GatherAnimationClips(clips);
clips.Gather(_Animations);
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
#region Play Management
/************************************************************************************************************************/
///
/// Returns the clip's name. This method is used to determine the dictionary key to use for an animation when
/// none is specified by the user, such as in .
///
public override object GetKey(AnimationClip clip)
{
return clip.name;
}
/************************************************************************************************************************/
/// [Coroutine]
/// Plays each clip in the array one after the other. Mainly useful for testing and
/// showcasing purposes.
///
public IEnumerator PlayAnimationsInSequence()
{
for (int i = 0; i < _Animations.Length; i++)
{
var state = Play(_Animations[i]);
if (state != null)
yield return state;
}
Stop();
}
/************************************************************************************************************************/
/// [Pro-Only] [Coroutine]
/// Cross fades between each clip in the array one after the other. Mainly useful for
/// testing and showcasing purposes.
///
public IEnumerator CrossFadeAnimationsInSequence(float fadeDuration = AnimancerPlayable.DefaultFadeDuration)
{
for (int i = 0; i < _Animations.Length; i++)
{
var state = Play(_Animations[i], fadeDuration);
if (state != null)
{
state.Time = 0;
yield return state;
}
}
Stop();
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
}
}