biography-of-lijie/Assets/GameMain/Scripts/UI/View/MainOverlayForm.cs

269 lines
7.6 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Definition.Enum;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
public class MainOverlayForm : UGuiForm
{
[SerializeField] private Image _cueImage;
[SerializeField] private List<Sprite> _cueBindings = new List<Sprite>();
[SerializeField] private float _showDuration = 0.2f;
[SerializeField] private float _hideDuration = 0.2f;
private static int _dispatchCount;
private Coroutine _transitionCoroutine;
private bool _isClosingByCue;
private Vector3 _baseScale = Vector3.one;
private bool _baseScaleInitialized;
public static void DispatchCue(EmphasisType emphasis)
{
if (GameEntry.UI == null)
{
return;
}
UGuiForm existingForm = GameEntry.UI.GetUIForm(UIFormId.MainOverlayForm);
if (emphasis == EmphasisType.EntityCueClose)
{
if (existingForm is MainOverlayForm overlay)
{
overlay.PlayHideAndClose();
}
return;
}
if (emphasis != EmphasisType.EntityCue)
{
return;
}
if (existingForm is MainOverlayForm overlayForm)
{
overlayForm.ShowNextCue();
return;
}
int? formSerialId = GameEntry.UI.OpenUIForm(UIFormId.MainOverlayForm);
if (!formSerialId.HasValue)
{
Log.Warning("MainOverlayForm open failed. Check UIForm.txt config and prefab asset.");
}
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
EnsureBaseScaleInitialized();
ShowNextCue();
}
protected override void OnClose(bool isShutdown, object userData)
{
StopTransition();
HideCueImage(clearSprite: true);
base.OnClose(isShutdown, userData);
}
private void ShowNextCue()
{
if (_cueImage == null)
{
Log.Warning("MainOverlayForm cue image is missing.");
return;
}
if (_cueBindings == null || _cueBindings.Count == 0)
{
HideCueImage(clearSprite: false);
Log.Warning("MainOverlayForm cue bindings are empty.");
return;
}
int index = _dispatchCount % _cueBindings.Count;
_dispatchCount++;
Sprite sprite = _cueBindings[index];
if (sprite == null)
{
HideCueImage(clearSprite: false);
return;
}
EnsureBaseScaleInitialized();
StopTransition();
_transitionCoroutine = StartCoroutine(PlayShowRoutine(sprite));
}
private void PlayHideAndClose()
{
if (_isClosingByCue)
{
return;
}
if (_cueImage == null)
{
if (GameEntry.UI != null && UIForm != null)
{
GameEntry.UI.CloseUIForm(UIForm);
}
return;
}
StopTransition();
_transitionCoroutine = StartCoroutine(PlayHideAndCloseRoutine());
}
private IEnumerator PlayShowRoutine(Sprite sprite)
{
_cueImage.sprite = sprite;
_cueImage.SetNativeSize();
_cueImage.gameObject.SetActive(true);
SetCueVisual(0f, 0f);
yield return PlayLerp(0f, 1f, 0f, 0.6f, _showDuration);
_transitionCoroutine = null;
}
private IEnumerator PlayHideAndCloseRoutine()
{
_isClosingByCue = true;
float fromAlpha = _cueImage.color.a;
float fromScale = GetCurrentScale01();
yield return PlayLerp(fromAlpha, 0f, fromScale, 0f, _hideDuration);
HideCueImage(clearSprite: true);
_isClosingByCue = false;
_transitionCoroutine = null;
if (GameEntry.UI != null && UIForm != null)
{
GameEntry.UI.CloseUIForm(UIForm);
}
}
private IEnumerator PlayLerp(float fromAlpha, float toAlpha, float fromScale, float toScale, float duration)
{
if (_cueImage == null)
{
yield break;
}
float safeDuration = Mathf.Max(0f, duration);
if (safeDuration <= 0f)
{
SetCueVisual(toAlpha, toScale);
yield break;
}
float elapsed = 0f;
while (elapsed < safeDuration)
{
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / safeDuration);
float alpha = Mathf.Lerp(fromAlpha, toAlpha, t);
float scale = Mathf.Lerp(fromScale, toScale, t);
SetCueVisual(alpha, scale);
yield return null;
}
SetCueVisual(toAlpha, toScale);
}
private void SetCueVisual(float alpha, float scale01)
{
if (_cueImage == null)
{
return;
}
Color color = _cueImage.color;
color.a = Mathf.Clamp01(alpha);
_cueImage.color = color;
RectTransform rectTransform = _cueImage.rectTransform;
if (rectTransform == null)
{
return;
}
float safeScale = Mathf.Clamp01(scale01);
rectTransform.localScale = _baseScale * safeScale;
}
private float GetCurrentScale01()
{
if (_cueImage == null)
{
return 1f;
}
EnsureBaseScaleInitialized();
RectTransform rectTransform = _cueImage.rectTransform;
if (rectTransform == null)
{
return 1f;
}
float ratioX = Mathf.Abs(_baseScale.x) > 0.0001f ? rectTransform.localScale.x / _baseScale.x : 1f;
float ratioY = Mathf.Abs(_baseScale.y) > 0.0001f ? rectTransform.localScale.y / _baseScale.y : 1f;
return Mathf.Clamp01((ratioX + ratioY) * 0.5f);
}
private void EnsureBaseScaleInitialized()
{
if (_baseScaleInitialized)
{
return;
}
if (_cueImage == null || _cueImage.rectTransform == null)
{
_baseScale = Vector3.one;
_baseScaleInitialized = true;
return;
}
_baseScale = _cueImage.rectTransform.localScale;
if (_baseScale == Vector3.zero)
{
_baseScale = Vector3.one;
}
_baseScaleInitialized = true;
}
private void StopTransition()
{
if (_transitionCoroutine != null)
{
StopCoroutine(_transitionCoroutine);
_transitionCoroutine = null;
}
_isClosingByCue = false;
}
private void HideCueImage(bool clearSprite)
{
if (_cueImage == null)
{
return;
}
_cueImage.gameObject.SetActive(false);
SetCueVisual(0f, 0f);
if (clearSprite)
{
_cueImage.sprite = null;
}
}
}
}