using System; using UnityEngine; using UnityEngine.EventSystems; namespace LeTai.TrueShadow { public class AnimatedBiStateButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler { public enum State { Up, AnimateDown, Down, AnimateUp, } public float animationDuration = .1f; public AnimationCurve animationCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); public bool useEnterExitEvents = true; public event Action willPress; public event Action willRelease; protected State state = State.Up; /// /// 0 = fully up /// 1 = fully down /// protected float pressAmount = 0; protected bool IsAnimating => state == State.AnimateDown || state == State.AnimateUp; void Update() { PollPointerUp(); DoAnimation(); } void DoAnimation() { if (!IsAnimating) return; if (state == State.AnimateDown) { pressAmount += Time.deltaTime / animationDuration; } else if (state == State.AnimateUp) { pressAmount -= Time.deltaTime / animationDuration; } pressAmount = Mathf.Clamp01(pressAmount); var animationProgress = pressAmount; if (state == State.AnimateUp) animationProgress = 1 - animationProgress; animationProgress = animationCurve.Evaluate(animationProgress); if (state == State.AnimateUp) animationProgress = 1 - animationProgress; Animate(animationProgress); if (state == State.AnimateDown && pressAmount == 1) { state = State.Down; } if (state == State.AnimateUp && pressAmount == 0) { state = State.Up; } } protected void Press() { if (state != State.Down && state != State.AnimateDown) { OnWillPress(); state = State.AnimateDown; } } protected void Release() { if (state != State.Up && state != State.AnimateUp) { OnWillRelease(); state = State.AnimateUp; } } /// /// Pointer Up event does not fire on an object if it was not the one receive the Pointer Down event. /// void PollPointerUp() { if (useEnterExitEvents && (state == State.Down || state == State.AnimateDown) && !Input.GetMouseButton(0)) { Release(); } } /// /// NOP if not overrided /// /// conformed to protected virtual void Animate(float visualPressAmount) { } public void OnPointerDown(PointerEventData eventData) { Press(); } public void OnPointerUp(PointerEventData eventData) { Release(); } public void OnPointerEnter(PointerEventData eventData) { if (useEnterExitEvents && Input.GetMouseButton(0)) Press(); } public void OnPointerExit(PointerEventData eventData) { if (useEnterExitEvents) Release(); } protected virtual void OnWillPress() { willPress?.Invoke(); } protected virtual void OnWillRelease() { willRelease?.Invoke(); } } }