// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved. // This code can only be used under the standard Unity Asset Store End User License Agreement // A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Doozy.Runtime.Common.Extensions; using Doozy.Runtime.Common.Utils; using Doozy.Runtime.Reactor.Animators.Internal; using UnityEngine; using UnityEngine.Events; // ReSharper disable MemberCanBePrivate.Global namespace Doozy.Runtime.Reactor { /// Specialized controller that controls multiple ReactorAnimators at the same time [AddComponentMenu("Doozy/Reactor/Reactor Controller")] public class ReactorController : MonoBehaviour { #if UNITY_EDITOR [UnityEditor.MenuItem("GameObject/Doozy/Reactor/Reactor Controller", false, 6)] private static void CreateComponent(UnityEditor.MenuCommand menuCommand) { GameObjectUtils.AddToScene(false, true); } #endif /// /// Describes the controller working mode /// public enum Mode { /// Set animators manually without any logic in Awake() Manual, /// Automatically search and populate the controlled animators list in Awake() Automatic } /// Controller name public string ControllerName; /// Controller animators behaviour on Start public AnimatorBehaviour OnStartBehaviour = AnimatorBehaviour.Disabled; /// Controller animators behaviour on Enable public AnimatorBehaviour OnEnableBehaviour = AnimatorBehaviour.Disabled; /// Override the OnStart and OnEnable animator behaviours for all connected animators public bool OverrideAnimatorsBehaviors; /// Determines if the controller should automatically search for animators or not public Mode ControllerMode = Mode.Manual; [SerializeField] private List Animators; /// All the animators controlled by this controller public List animators { get => Animators ?? (Animators = new List()); private set => Animators = value; } /// Check if this controller controls any animators public bool hasAnimators => animators.Count > 0; /// Flag used to mark when the controller has been initialized public bool initialized { get; private set; } protected virtual void Awake() { if (!Application.isPlaying) return; initialized = false; Initialize(); } protected virtual void OnEnable() { if (!Application.isPlaying) return; RunBehaviour(OnEnableBehaviour); } protected virtual void Start() { if (!Application.isPlaying) return; RunBehaviour(OnStartBehaviour); } /// Start the controller initialization process protected virtual void Initialize() { if (initialized) return; switch (ControllerMode) { case Mode.Automatic: animators = GetComponentsInChildren().Where(c => c.isActiveAndEnabled).ToList(); break; case Mode.Manual: //ignored break; default: throw new ArgumentOutOfRangeException(); } if (!hasAnimators) { initialized = true; return; } if (OverrideAnimatorsBehaviors) { foreach (ReactorAnimator animator in animators.RemoveNulls()) { animator.OnStartBehaviour = AnimatorBehaviour.Disabled; animator.OnEnableBehaviour = AnimatorBehaviour.Disabled; } } initialized = true; } // Execute the given behaviour /// Controller behaviour protected virtual void RunBehaviour(AnimatorBehaviour behaviour) { if (behaviour == AnimatorBehaviour.Disabled) return; bool animatorsInitialized = true; foreach (ReactorAnimator a in animators.RemoveNulls()) if (!a.animatorInitialized) animatorsInitialized = false; if (!initialized || !animatorsInitialized) { DelayExecution(() => RunBehaviour(behaviour)); return; } InitializeAnimators(); switch (behaviour) { case AnimatorBehaviour.PlayForward: Play(PlayDirection.Forward); break; case AnimatorBehaviour.PlayReverse: Play(PlayDirection.Reverse); break; case AnimatorBehaviour.SetFromValue: SetProgressAtZero(); break; case AnimatorBehaviour.SetToValue: SetProgressAtOne(); break; default: throw new ArgumentOutOfRangeException(nameof(behaviour), behaviour, null); } } /// Delay any execution until the controller has been initialized /// Unity action callback protected void DelayExecution(UnityAction callback) => StartCoroutine(ExecuteAfterControllerInitialized(callback)); /// Invoke the given callback after the controller has been initialized /// Unity action callback protected IEnumerator ExecuteAfterControllerInitialized(UnityAction callback) { yield return new WaitUntil(() => initialized); callback?.Invoke(); } /// Initialize all the controlled animators (update settings and set the initialized flag) public void InitializeAnimators() { foreach (var a in animators.RemoveNulls()) a.Initialize(); } /// Update the initial values for the animators controlled by this controller public void UpdateValues() { foreach (var a in animators.RemoveNulls()) a.UpdateValues(); } /// Set all the controlled animators animations at 100% (at the end, or the 'To' value) public void SetProgressAtOne() { foreach (var a in animators.RemoveNulls()) a.SetProgressAtOne(); } /// Set all the controlled animators animations at 0% (at the start, or the 'From' value) public void SetProgressAtZero() { foreach (var a in animators.RemoveNulls()) a.SetProgressAtZero(); } /// Set all the controlled animators animations at the given progress value /// Target progress [0,1] public void SetProgressAt(float targetProgress) { foreach (var a in animators.RemoveNulls()) a.SetProgressAt(targetProgress); } /// Play all the controlled animators animations at the given progress value from the current value /// To progress [0,1] public void PlayToProgress(float toProgress) { foreach (var a in animators.RemoveNulls()) a.PlayToProgress(toProgress); } /// Play all the controlled animators animations from the given progress value to the current value /// From progress [0,1] public void PlayFromProgress(float fromProgress) { foreach (var a in animators.RemoveNulls()) a.PlayFromProgress(fromProgress); } /// Play all the controlled animators animations from the given progress value to the given progress value /// From progress [0,1] /// To progress [0,1] public void PlayFromToProgress(float fromProgress, float toProgress) { foreach (var a in animators.RemoveNulls()) a.PlayFromToProgress(fromProgress, toProgress); } /// Play all the controlled animators animations all the way in the given direction /// Play direction (Forward or Reverse) public void Play(PlayDirection playDirection) { foreach (var a in animators.RemoveNulls()) a.Play(playDirection); } /// Play all the controlled animators animations all the way /// Play the animation in reverse? public void Play(bool inReverse = false) { foreach (var a in animators.RemoveNulls()) a.Play(inReverse); } /// Reset all the controlled animators animations to their initial values (if the animations are enabled) /// If true, forced will ignore if the animation is enabled or not public void ResetToStartValues(bool forced = false) { foreach (var a in animators.RemoveNulls()) a.ResetToStartValues(forced); } /// Stop all the controlled animators animations public void Stop() { foreach (var a in animators.RemoveNulls()) a.Stop(); } /// Finish all the controlled animators animations public void Finish() { foreach (var a in animators.RemoveNulls()) a.Finish(); } /// /// Reverse all the controlled animators animations direction while playing. /// Works only if the animations are active (either playing or paused) /// public void Reverse() { foreach (var a in animators.RemoveNulls()) a.Reverse(); } /// Rewind all the controlled animators animations to the start values public void Rewind() { foreach (var a in animators.RemoveNulls()) a.Rewind(); } /// /// Pause all the controlled animators animations. /// Works only if the animations are playing. /// public void Pause() { foreach (var a in animators.RemoveNulls()) a.Pause(); } /// /// Resume all the controlled animators animations. /// Works only if the animations are paused. /// public void Resume() { foreach (var a in animators.RemoveNulls()) a.Resume(); } /// Refresh all the controlled animators animations target and update values public void UpdateSettings() { foreach (var a in animators.RemoveNulls()) a.UpdateSettings(); } /// /// Get the max start delay of all the controlled animators animations. /// For random values it returns the max value. /// public float GetStartDelay() { float result = 0f; foreach (ReactorAnimator animator in animators.RemoveNulls()) result = Mathf.Max(result, animator.GetStartDelay()); return result; } /// /// Get the maximum duration (without start delay) of all the controlled animators animations. /// For random values it returns the max value. /// public float GetDuration() { float result = 0f; foreach (ReactorAnimator animator in animators.RemoveNulls()) result = Mathf.Max(result, animator.GetDuration()); return result; } /// Get the maxi start delay + duration of all the controlled animators animations. public float GetTotalDuration() { return GetStartDelay() + GetDuration(); } } }