// 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.Collections.Generic; using Doozy.Runtime.Common.Layouts; using Doozy.Runtime.Common.Utils; using Doozy.Runtime.Reactor; using Doozy.Runtime.Reactor.Animations; using Doozy.Runtime.Reactor.Ticker; using Doozy.Runtime.UIManager.Containers; using UnityEngine; using UnityEngine.UI; // ReSharper disable MemberCanBePrivate.Global namespace Doozy.Runtime.UIManager.Animators { /// /// Specialized animator component used to animate a RectTransform’s position, rotation, scale and alpha /// by listening to a target UIContainer (controller) show/hide commands. /// [AddComponentMenu("Doozy/UI/Containers/Animators/UIContainer UIAnimator")] [RequireComponent(typeof(CanvasGroup))] [RequireComponent(typeof(RectTransform))] public class UIContainerUIAnimator : BaseUIContainerAnimator { private CanvasGroup m_CanvasGroup; /// Reference to the CanvasGroup component public CanvasGroup canvasGroup => m_CanvasGroup ? m_CanvasGroup : m_CanvasGroup = GetComponent(); [SerializeField] private UIAnimation ShowAnimation; /// Container Show Animation public UIAnimation showAnimation => ShowAnimation ?? (ShowAnimation = new UIAnimation(rectTransform)); [SerializeField] private UIAnimation HideAnimation; /// Container Hide Animation public UIAnimation hideAnimation => HideAnimation ?? (HideAnimation = new UIAnimation(rectTransform)); public bool anyAnimationIsActive => showAnimation.isActive || hideAnimation.isActive; private bool isInLayoutGroup { get; set; } private Vector3 localPosition { get; set; } private UIBehaviourHandler uiBehaviourHandler { get; set; } private bool updateStartPositionInLateUpdate { get; set; } #if UNITY_EDITOR protected override void Reset() { ResetAnimation(showAnimation); ResetAnimation(hideAnimation); showAnimation.animationType = UIAnimationType.Show; showAnimation.Move.enabled = true; showAnimation.Move.fromDirection = MoveDirection.Left; hideAnimation.animationType = UIAnimationType.Hide; hideAnimation.Move.enabled = true; hideAnimation.Move.toDirection = MoveDirection.Right; base.Reset(); } #endif protected override void Awake() { if (!Application.isPlaying) return; animatorInitialized = false; m_RectTransform = GetComponent(); m_CanvasGroup = GetComponent(); UpdateLayout(); } protected override void OnEnable() { if (!Application.isPlaying) return; base.OnEnable(); updateStartPositionInLateUpdate = true; } protected override void OnDisable() { if (!Application.isPlaying) return; base.OnDisable(); if (showAnimation.isPlaying) showAnimation.SetProgressAtOne(); if (hideAnimation.isPlaying) hideAnimation.SetProgressAtOne(); RefreshLayout(); } protected override void OnDestroy() { base.OnDestroy(); ShowAnimation?.Recycle(); HideAnimation?.Recycle(); } private void LateUpdate() { if (!animatorInitialized) return; if (!isInLayoutGroup) return; if (!isConnected) return; if (controller.visibilityState != VisibilityState.Visible) return; if (anyAnimationIsActive) return; if (!updateStartPositionInLateUpdate && localPosition == rectTransform.localPosition) return; if (CanvasUpdateRegistry.IsRebuildingLayout()) return; RefreshLayout(); UpdateStartPosition(); } private void UpdateLayout() { isInLayoutGroup = rectTransform.IsInLayoutGroup(); uiBehaviourHandler = null; if (!isInLayoutGroup) return; LayoutGroup layout = rectTransform.GetLayoutGroupInParent(); if (layout == null) return; uiBehaviourHandler = layout.GetUIBehaviourHandler(); System.Diagnostics.Debug.Assert(uiBehaviourHandler != null, nameof(uiBehaviourHandler) + " != null"); uiBehaviourHandler.SetDirty(); } /// Refresh the layout the container is in private void RefreshLayout() { if (uiBehaviourHandler == null) return; uiBehaviourHandler.RefreshLayout(); } /// Update the start position of the container public void UpdateStartPosition() { // if (name.Contains("#")) Debug.Log($"({Time.frameCount}) [{name}] {nameof(UpdateStartPosition)}"); Vector3 anchoredPosition3D = rectTransform.anchoredPosition3D; showAnimation.startPosition = anchoredPosition3D; hideAnimation.startPosition = anchoredPosition3D; if (showAnimation.Move.isPlaying) showAnimation.Move.UpdateValues(); if (hideAnimation.Move.isPlaying) hideAnimation.Move.UpdateValues(); localPosition = rectTransform.localPosition; updateStartPositionInLateUpdate = false; } /// Refresh the layout and then the start position of the container private void RefreshStartPosition() { if (!isConnected) return; if (anyAnimationIsActive) return; if (controller.visibilityState != VisibilityState.Visible) return; RefreshLayout(); UpdateStartPosition(); } /// Connect to Controller protected override void ConnectToController() { base.ConnectToController(); if (!controller) return; controller.showReactions.Add(showAnimation.Move); controller.showReactions.Add(showAnimation.Rotate); controller.showReactions.Add(showAnimation.Scale); controller.showReactions.Add(showAnimation.Fade); controller.hideReactions.Add(hideAnimation.Move); controller.hideReactions.Add(hideAnimation.Rotate); controller.hideReactions.Add(hideAnimation.Scale); controller.hideReactions.Add(hideAnimation.Fade); } /// Disconnect from Controller protected override void DisconnectFromController() { base.DisconnectFromController(); if (!controller) return; controller.showReactions.Remove(showAnimation.Move); controller.showReactions.Remove(showAnimation.Rotate); controller.showReactions.Remove(showAnimation.Scale); controller.showReactions.Remove(showAnimation.Fade); controller.hideReactions.Remove(hideAnimation.Move); controller.hideReactions.Remove(hideAnimation.Rotate); controller.hideReactions.Remove(hideAnimation.Scale); controller.hideReactions.Remove(hideAnimation.Fade); } /// Play the show animation public override void Show() { if (reversingShow) { showAnimation.OnFinishCallback.RemoveListener(OnReverseShowComplete); reversingShow = false; } showAnimation.Play(PlayDirection.Forward); if (animatorInitialized && isInLayoutGroup) updateStartPositionInLateUpdate = true; } /// Reverse the show animation (if playing) public override void ReverseShow() { if (showAnimation.isPlaying) { showAnimation.OnFinishCallback.AddListener(OnReverseShowComplete); showAnimation.Reverse(); reversingShow = true; return; } Hide(); } private void OnReverseShowComplete() { InstantHide(); showAnimation.OnFinishCallback.RemoveListener(OnReverseShowComplete); reversingShow = false; } /// Play the hide animation public override void Hide() { if (reversingHide) { hideAnimation.OnFinishCallback.RemoveListener(OnReverseHideComplete); reversingHide = false; } if (animatorInitialized && isInLayoutGroup) RefreshStartPosition(); hideAnimation.Play(PlayDirection.Forward); } /// Reverse the hide animation (if playing) public override void ReverseHide() { if (hideAnimation.isPlaying) { hideAnimation.OnFinishCallback.AddListener(OnReverseHideComplete); hideAnimation.Reverse(); reversingHide = true; return; } Show(); } private void OnReverseHideComplete() { InstantShow(); hideAnimation.OnFinishCallback.RemoveListener(OnReverseHideComplete); reversingHide = false; updateStartPositionInLateUpdate = true; } /// Set show animation's progress at one public override void InstantShow() { showAnimation.SetProgressAtOne(); if (animatorInitialized && isInLayoutGroup) updateStartPositionInLateUpdate = true; } /// Set hide animation's progress at one public override void InstantHide() { if (animatorInitialized && isInLayoutGroup) RefreshStartPosition(); hideAnimation.SetProgressAtOne(); } /// Update the animations settings (if a colorTarget is referenced) public override void UpdateSettings() { showAnimation.SetTarget(rectTransform, canvasGroup); hideAnimation.SetTarget(rectTransform, canvasGroup); } /// Stop all animations public override void StopAllReactions() { showAnimation.Stop(); hideAnimation.Stop(); } /// Reset all the reactions to their initial values (if the animation is enabled) /// If true, forced will ignore if the animation is enabled or not public override void ResetToStartValues(bool forced = false) { if (m_RectTransform == null) return; if (showAnimation.isActive) showAnimation.Stop(); if (hideAnimation.isActive) hideAnimation.Stop(); showAnimation.ResetToStartValues(forced); hideAnimation.ResetToStartValues(forced); rectTransform.anchoredPosition3D = showAnimation.startPosition; rectTransform.localEulerAngles = showAnimation.startRotation; rectTransform.localScale = showAnimation.startScale; canvasGroup.alpha = showAnimation.startAlpha; #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(rectTransform); UnityEditor.SceneView.RepaintAll(); #endif } /// Set animation heartbeat public override List SetHeartbeat() { var list = new List(); for (int i = 0; i < 8; i++) list.Add(new T()); showAnimation.Move.SetHeartbeat(list[0]); showAnimation.Rotate.SetHeartbeat(list[1]); showAnimation.Scale.SetHeartbeat(list[2]); showAnimation.Fade.SetHeartbeat(list[3]); hideAnimation.Move.SetHeartbeat(list[4]); hideAnimation.Rotate.SetHeartbeat(list[5]); hideAnimation.Scale.SetHeartbeat(list[6]); hideAnimation.Fade.SetHeartbeat(list[7]); return list; } /// Set a new start position value (RectTransform.anchoredPosition3D) for all animations /// New start position public void SetStartPosition(Vector3 value) { showAnimation.startPosition = value; hideAnimation.startPosition = value; } /// Set a new start rotation value (RectTransform.localEulerAngles) for both show and hide animations /// New start rotation public void SetStartRotation(Vector3 value) { showAnimation.startRotation = value; hideAnimation.startRotation = value; } /// Set a new start scale value (RectTransform.localScale) for both show and hide animations /// New start scale public void SetStartScale(Vector3 value) { showAnimation.startScale = value; hideAnimation.startScale = value; } /// Set a new start alpha value (CanvasGroup.alpha) for both show and hide animations /// New start scale public void SetStartAlpha(float value) { showAnimation.startAlpha = value; hideAnimation.startAlpha = value; } private static void ResetAnimation(UIAnimation target) { target.Move.Reset(); target.Rotate.Reset(); target.Scale.Reset(); target.Fade.Reset(); target.Move.fromReferenceValue = ReferenceValue.StartValue; target.Rotate.fromReferenceValue = ReferenceValue.StartValue; target.Scale.fromReferenceValue = ReferenceValue.StartValue; target.Fade.fromReferenceValue = ReferenceValue.StartValue; target.Move.settings.duration = UIContainer.k_DefaultAnimationDuration; target.Rotate.settings.duration = UIContainer.k_DefaultAnimationDuration; target.Scale.settings.duration = UIContainer.k_DefaultAnimationDuration; target.Fade.settings.duration = UIContainer.k_DefaultAnimationDuration; } } }