using System; using System.Collections; using Cute; using UnityEngine; namespace Wizard; public class ChatOpenCloseAnimation : MonoBehaviour { public enum eState { CLOSED, OPENED, CLOSING, OPENING } public const float CLOSE_HEIGHT = 0f; [SerializeField] private GameObject _animationObj; [SerializeField] private bool _isActiveUpdate; [SerializeField] private float _openPositionY; [SerializeField] private float _closePositionY = -60f; [SerializeField] private float _openAnimationTime = 0.3f; [SerializeField] private float _closeAnimationTime = 0.2f; private Coroutine _coroutinAnimation; public eState State { get; private set; } public bool IsOpen { get { if (State != eState.OPENED) { return State == eState.OPENING; } return true; } } public bool IsMoving { get; private set; } public float CurrentPosHeight => _animationObj.transform.localPosition.y - _closePositionY; public float OpenHeight => _openPositionY - _closePositionY; public float AnimationTime { get { if (!IsOpen) { return _closeAnimationTime; } return _openAnimationTime; } } public bool IsAnimationStartFromOpenedOrClosed { get { if (State != eState.OPENING || !Mathf.Approximately(CurrentPosHeight, 0f)) { if (State == eState.CLOSING) { return Mathf.Approximately(CurrentPosHeight, OpenHeight); } return false; } return true; } } public void Init(bool isOpenedDefault) { ChangeOpenedClosedState(isOpenedDefault); } public void ToggleStateAndStartAnimation() { switch (State) { case eState.CLOSED: case eState.CLOSING: StartOpenAnimation(); break; case eState.OPENED: case eState.OPENING: StartCloseAnimation(); break; } } public void StartCloseAnimation(Action onAnimationEndCallBack = null) { if (IsOpen) { if (_coroutinAnimation != null) { StopCoroutine(_coroutinAnimation); } _coroutinAnimation = StartCoroutine(CloseAnimation(onAnimationEndCallBack)); } } public void StartOpenAnimation() { if (!IsOpen) { if (_coroutinAnimation != null) { StopCoroutine(_coroutinAnimation); } _animationObj.SetActive(value: true); _coroutinAnimation = StartCoroutine(OpenAnimation()); } } private IEnumerator OpenAnimation() { State = eState.OPENING; Vector3 basePos = _animationObj.transform.localPosition; IsMoving = true; float durationTime = _openAnimationTime * (1f - CurrentPosHeight / OpenHeight); CustomEasing easing = new CustomEasing(CustomEasing.eType.outQuad, basePos.y, _openPositionY, durationTime); while (easing.IsMoving) { yield return null; float curVal = easing.GetCurVal(Time.deltaTime); _animationObj.transform.localPosition = new Vector3(basePos.x, curVal, basePos.z); if (State != eState.OPENING) { yield break; } } IsMoving = false; ChangeOpenedClosedState(isOpened: true); } private IEnumerator CloseAnimation(Action onAnimationEndCallBack) { State = eState.CLOSING; Vector3 basePos = _animationObj.transform.localPosition; IsMoving = true; float durationTime = _closeAnimationTime * CurrentPosHeight / OpenHeight; CustomEasing easing = new CustomEasing(CustomEasing.eType.outQuad, basePos.y, _closePositionY, durationTime); while (easing.IsMoving) { yield return null; float curVal = easing.GetCurVal(Time.deltaTime); _animationObj.transform.localPosition = new Vector3(basePos.x, curVal, basePos.z); if (State != eState.CLOSING) { yield break; } } IsMoving = false; ChangeOpenedClosedState(isOpened: false); onAnimationEndCallBack.Call(); } private void ChangeOpenedClosedState(bool isOpened) { State = (isOpened ? eState.OPENED : eState.CLOSED); Vector3 localPosition = _animationObj.transform.localPosition; float y = (isOpened ? _openPositionY : _closePositionY); _animationObj.transform.localPosition = new Vector3(localPosition.x, y, localPosition.z); if (_isActiveUpdate) { _animationObj.SetActive(isOpened); } } }