OldBlueWater/BlueWater/Assets/Doozy/Runtime/UIManager/Animators/UISelectableUIAnimator.cs

353 lines
15 KiB
C#
Raw Normal View History

// 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.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.Components;
using UnityEngine;
using UnityEngine.UI;
// ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBePrivate.Global
namespace Doozy.Runtime.UIManager.Animators
{
/// <summary>
/// Specialized animator component used to animate a RectTransforms position, rotation, scale and alpha
/// by listening to a target UISelectable (controller) selection state changes.
/// </summary>
[RequireComponent(typeof(CanvasGroup))]
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("Doozy/UI/Components/Animators/UISelectable UIAnimator")]
public class UISelectableUIAnimator : BaseUISelectableAnimator
{
private CanvasGroup m_CanvasGroup;
/// <summary> Reference to the CanvasGroup component </summary>
public CanvasGroup canvasGroup => m_CanvasGroup ? m_CanvasGroup : m_CanvasGroup = GetComponent<CanvasGroup>();
[SerializeField] private UIAnimation NormalAnimation;
/// <summary> Animation for the Normal selection state </summary>
public UIAnimation normalAnimation => NormalAnimation ?? (NormalAnimation = new UIAnimation(rectTransform));
[SerializeField] private UIAnimation HighlightedAnimation;
/// <summary> Animation for the Highlighted selection state </summary>
public UIAnimation highlightedAnimation => HighlightedAnimation ?? (HighlightedAnimation = new UIAnimation(rectTransform));
[SerializeField] private UIAnimation PressedAnimation;
/// <summary> Animation for the Pressed selection state </summary>
public UIAnimation pressedAnimation => PressedAnimation ?? (PressedAnimation = new UIAnimation(rectTransform));
[SerializeField] private UIAnimation SelectedAnimation;
/// <summary> Animation for the Selected selection state </summary>
public UIAnimation selectedAnimation => SelectedAnimation ?? (SelectedAnimation = new UIAnimation(rectTransform));
[SerializeField] private UIAnimation DisabledAnimation;
/// <summary> Animation for the Disabled selection state </summary>
public UIAnimation disabledAnimation => DisabledAnimation ?? (DisabledAnimation = new UIAnimation(rectTransform));
/// <summary> Returns TRUE if any animation is active </summary>
public bool anyAnimationIsActive =>
normalAnimation.isActive ||
highlightedAnimation.isActive ||
pressedAnimation.isActive ||
selectedAnimation.isActive ||
disabledAnimation.isActive;
private bool isInLayoutGroup { get; set; }
private Vector3 localPosition { get; set; }
private UIBehaviourHandler uiBehaviourHandler { get; set; }
private bool updateStartPositionInLateUpdate { get; set; }
private bool playStateAnimationFromLateUpdate { get; set; }
/// <summary> Get the Animation triggered by the given selection state </summary>
/// <param name="state"> Target selection state </param>
public UIAnimation GetAnimation(UISelectionState state) =>
state switch
{
UISelectionState.Normal => normalAnimation,
UISelectionState.Highlighted => highlightedAnimation,
UISelectionState.Pressed => pressedAnimation,
UISelectionState.Selected => selectedAnimation,
UISelectionState.Disabled => disabledAnimation,
_ => throw new ArgumentOutOfRangeException(nameof(state), state, null)
};
#if UNITY_EDITOR
protected override void Reset()
{
foreach (UISelectionState state in UISelectable.uiSelectionStates)
ResetAnimation(GetAnimation(state));
NormalAnimation.animationType = UIAnimationType.Reset;
NormalAnimation.Move.enabled = true;
NormalAnimation.Rotate.enabled = true;
NormalAnimation.Scale.enabled = true;
NormalAnimation.Fade.enabled = true;
base.Reset();
}
#endif
protected override void Awake()
{
if (!Application.isPlaying) return;
animatorInitialized = false;
m_RectTransform = GetComponent<RectTransform>();
m_CanvasGroup = GetComponent<CanvasGroup>();
UpdateLayout();
}
protected override void OnEnable()
{
if (!Application.isPlaying) return;
playStateAnimationFromLateUpdate = true;
base.OnEnable();
UpdateLayout();
updateStartPositionInLateUpdate = true;
}
protected override void OnDisable()
{
if (!Application.isPlaying) return;
base.OnDisable();
RefreshLayout();
}
protected override void OnDestroy()
{
base.OnDestroy();
foreach (UISelectionState state in UISelectable.uiSelectionStates)
GetAnimation(state)?.Recycle();
}
private void OnRectTransformDimensionsChange()
{
if (!isConnected) return;
if (!isInLayoutGroup) return;
updateStartPositionInLateUpdate = true;
}
private void LateUpdate()
{
if (!animatorInitialized) return;
if (playStateAnimationFromLateUpdate)
{
if (isConnected)
{
Play(controller.currentUISelectionState);
playStateAnimationFromLateUpdate = false;
}
}
if (!isInLayoutGroup) return;
if (!isConnected) return;
if (anyAnimationIsActive) return;
if (!updateStartPositionInLateUpdate && localPosition == rectTransform.localPosition) return;
if (controller.currentUISelectionState != UISelectionState.Normal) 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();
}
/// <summary> Refresh the layout the selectable is in </summary>
private void RefreshLayout()
{
if (uiBehaviourHandler == null) return;
uiBehaviourHandler.RefreshLayout();
}
/// <summary> Update the start position of the selectable </summary>
public void UpdateStartPosition()
{
foreach (UISelectionState state in UISelectable.uiSelectionStates)
{
UIAnimation uiAnimation = GetAnimation(state);
uiAnimation.startPosition = rectTransform.anchoredPosition3D;
if (uiAnimation.Move.isPlaying) uiAnimation.Move.UpdateValues();
}
localPosition = rectTransform.localPosition;
updateStartPositionInLateUpdate = false;
}
/// <summary> Returns True if the givens selection state is enabled and the animation is not null. </summary>
/// <param name="state"> Selection state </param>
public override bool IsStateEnabled(UISelectionState state) =>
GetAnimation(state).isEnabled;
/// <summary> Update the animations settings </summary>
public override void UpdateSettings()
{
foreach (UISelectionState state in UISelectable.uiSelectionStates)
GetAnimation(state).SetTarget(rectTransform, canvasGroup);
}
/// <summary> Stop all animations </summary>
public override void StopAllReactions()
{
foreach (UISelectionState state in UISelectable.uiSelectionStates)
GetAnimation(state)?.Stop();
}
/// <summary> Reset all the reactions to their initial values (if the animation is enabled) </summary>
/// <param name="forced"> If true, forced will ignore if the animation is enabled or not </param>
public override void ResetToStartValues(bool forced = false)
{
if (normalAnimation.isActive) normalAnimation.Stop();
if (highlightedAnimation.isActive) highlightedAnimation.Stop();
if (pressedAnimation.isActive) pressedAnimation.Stop();
if (selectedAnimation.isActive) selectedAnimation.Stop();
if (disabledAnimation.isActive) disabledAnimation.Stop();
normalAnimation.ResetToStartValues();
highlightedAnimation.ResetToStartValues();
pressedAnimation.ResetToStartValues();
selectedAnimation.ResetToStartValues();
disabledAnimation.ResetToStartValues();
if (m_RectTransform == null)
return;
rectTransform.anchoredPosition3D = normalAnimation.startPosition;
rectTransform.localEulerAngles = normalAnimation.startRotation;
rectTransform.localScale = normalAnimation.startScale;
canvasGroup.alpha = normalAnimation.startAlpha;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(rectTransform);
UnityEditor.SceneView.RepaintAll();
#endif
}
/// <summary> Set animation heartbeat </summary>*
public override List<Heartbeat> SetHeartbeat<T>()
{
var list = new List<Heartbeat>();
for (int i = 0; i < 20; i++) list.Add(new T());
normalAnimation.Move.SetHeartbeat(list[0]);
normalAnimation.Rotate.SetHeartbeat(list[1]);
normalAnimation.Scale.SetHeartbeat(list[2]);
normalAnimation.Fade.SetHeartbeat(list[3]);
highlightedAnimation.Move.SetHeartbeat(list[4]);
highlightedAnimation.Rotate.SetHeartbeat(list[5]);
highlightedAnimation.Scale.SetHeartbeat(list[6]);
highlightedAnimation.Fade.SetHeartbeat(list[7]);
pressedAnimation.Move.SetHeartbeat(list[8]);
pressedAnimation.Rotate.SetHeartbeat(list[9]);
pressedAnimation.Scale.SetHeartbeat(list[10]);
pressedAnimation.Fade.SetHeartbeat(list[11]);
selectedAnimation.Move.SetHeartbeat(list[12]);
selectedAnimation.Rotate.SetHeartbeat(list[13]);
selectedAnimation.Scale.SetHeartbeat(list[14]);
selectedAnimation.Fade.SetHeartbeat(list[15]);
disabledAnimation.Move.SetHeartbeat(list[16]);
disabledAnimation.Rotate.SetHeartbeat(list[17]);
disabledAnimation.Scale.SetHeartbeat(list[18]);
disabledAnimation.Fade.SetHeartbeat(list[19]);
return list;
}
/// <summary> Play the animation for the given selection state </summary>
/// <param name="state"> Selection state </param>
public override void Play(UISelectionState state)
{
if (playStateAnimationFromLateUpdate)
{
GetAnimation(state)?.SetProgressAtOne();
return;
}
GetAnimation(state)?.Play();
}
/// <summary> Set a new start position value (RectTransform.anchoredPosition3D) for all state animations </summary>
/// <param name="value"> New start position </param>
public void SetStartPosition(Vector3 value)
{
normalAnimation.startPosition = value;
highlightedAnimation.startPosition = value;
pressedAnimation.startPosition = value;
selectedAnimation.startPosition = value;
disabledAnimation.startPosition = value;
}
/// <summary> Set a new start rotation value (RectTransform.localEulerAngles) for all state animations </summary>
/// <param name="value"> New start rotation </param>
public void SetStartRotation(Vector3 value)
{
normalAnimation.startRotation = value;
highlightedAnimation.startRotation = value;
pressedAnimation.startRotation = value;
selectedAnimation.startRotation = value;
disabledAnimation.startRotation = value;
}
/// <summary> Set a new start scale value (RectTransform.localScale) for all state animations </summary>
/// <param name="value"> New start scale </param>
public void SetStartScale(Vector3 value)
{
normalAnimation.startScale = value;
highlightedAnimation.startScale = value;
pressedAnimation.startScale = value;
selectedAnimation.startScale = value;
disabledAnimation.startScale = value;
}
/// <summary> Set a new start alpha value (CanvasGroup.alpha) for all state animations </summary>
/// <param name="value"> New start scale </param>
public void SetStartAlpha(float value)
{
normalAnimation.startAlpha = value;
highlightedAnimation.startAlpha = value;
pressedAnimation.startAlpha = value;
selectedAnimation.startAlpha = value;
disabledAnimation.startAlpha = value;
}
/// <summary> Reset the give animation to a set of default values </summary>
/// <param name="target"> Target animation </param>
private static void ResetAnimation(UIAnimation target)
{
target.Move.Reset();
target.Rotate.Reset();
target.Scale.Reset();
target.Fade.Reset();
target.animationType = UIAnimationType.State;
target.Move.fromReferenceValue = ReferenceValue.CurrentValue;
target.Rotate.fromReferenceValue = ReferenceValue.CurrentValue;
target.Scale.fromReferenceValue = ReferenceValue.CurrentValue;
target.Fade.fromReferenceValue = ReferenceValue.CurrentValue;
target.Move.settings.duration = UISelectable.k_DefaultAnimationDuration;
target.Rotate.settings.duration = UISelectable.k_DefaultAnimationDuration;
target.Scale.settings.duration = UISelectable.k_DefaultAnimationDuration;
target.Fade.settings.duration = UISelectable.k_DefaultAnimationDuration;
}
}
}