// 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 /************************************************************************************************************************/ } }