376 lines
13 KiB
C#
376 lines
13 KiB
C#
using System.Collections;
|
|
using Event;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityGameFramework.Runtime;
|
|
|
|
namespace UI
|
|
{
|
|
public class ChapterTitleForm : UGuiForm
|
|
{
|
|
[SerializeField] private CanvasGroup _contentGroup;
|
|
[SerializeField] private Image _dimImage;
|
|
[SerializeField] private TMP_Text _titleText;
|
|
[SerializeField] private TMP_Text _subtitleText;
|
|
[SerializeField] private float _dimFadeInDuration = 0.2f;
|
|
[SerializeField] private float _preBlackDuration = 0.25f;
|
|
[SerializeField] private float _titleFadeInDelay = 0f;
|
|
[SerializeField] private float _fadeInDuration = 0.3f;
|
|
[SerializeField] private float _holdDuration = 1.2f;
|
|
[SerializeField] private float _fadeOutDuration = 0.3f;
|
|
[SerializeField] private float _dimFadeOutDuration = 0.2f;
|
|
|
|
private Coroutine _playCoroutine;
|
|
private int _requestId;
|
|
private int _chapterId;
|
|
private bool _hasPublishedCompletion;
|
|
private float _runtimeDimFadeInDuration;
|
|
private float _runtimePreBlackDuration;
|
|
private float _runtimeTitleFadeInDelay;
|
|
private float _runtimeTitleFadeInDuration;
|
|
private float _runtimeHoldDuration;
|
|
private float _runtimeTitleFadeOutDuration;
|
|
private float _runtimeDimFadeOutDuration;
|
|
|
|
protected override void OnOpen(object userData)
|
|
{
|
|
base.OnOpen(userData);
|
|
EnsureView();
|
|
ApplyContext(userData as ChapterTitleFormContext);
|
|
StartPlay();
|
|
}
|
|
|
|
protected override void OnClose(bool isShutdown, object userData)
|
|
{
|
|
StopPlay();
|
|
SetDimAlpha(0f);
|
|
SetTitleAlpha(0f);
|
|
if (!isShutdown)
|
|
{
|
|
PublishCompletionIfNeeded();
|
|
}
|
|
|
|
base.OnClose(isShutdown, userData);
|
|
}
|
|
|
|
private void EnsureView()
|
|
{
|
|
RectTransform rootRect = transform as RectTransform;
|
|
if (rootRect == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_contentGroup == null)
|
|
{
|
|
_contentGroup = CreateContentGroup(rootRect);
|
|
}
|
|
|
|
if (_contentGroup != null)
|
|
{
|
|
_contentGroup.alpha = 1f;
|
|
}
|
|
|
|
RectTransform contentRect = _contentGroup != null && _contentGroup.transform is RectTransform contentTransform
|
|
? contentTransform
|
|
: rootRect;
|
|
|
|
if (_dimImage == null)
|
|
{
|
|
_dimImage = CreateImage("Dim", contentRect, new Color(0f, 0f, 0f, 0.72f), true);
|
|
}
|
|
|
|
if (_titleText == null)
|
|
{
|
|
_titleText = CreateText("Title", contentRect, 108f, FontStyles.Bold, TextAlignmentOptions.Center);
|
|
RectTransform titleRect = _titleText.rectTransform;
|
|
titleRect.anchorMin = new Vector2(0.5f, 0.5f);
|
|
titleRect.anchorMax = new Vector2(0.5f, 0.5f);
|
|
titleRect.pivot = new Vector2(0.5f, 0.5f);
|
|
titleRect.sizeDelta = new Vector2(2200f, 220f);
|
|
titleRect.anchoredPosition = new Vector2(0f, 40f);
|
|
}
|
|
|
|
if (_subtitleText == null)
|
|
{
|
|
_subtitleText = CreateText("Subtitle", contentRect, 42f, FontStyles.Normal, TextAlignmentOptions.Center);
|
|
RectTransform subtitleRect = _subtitleText.rectTransform;
|
|
subtitleRect.anchorMin = new Vector2(0.5f, 0.5f);
|
|
subtitleRect.anchorMax = new Vector2(0.5f, 0.5f);
|
|
subtitleRect.pivot = new Vector2(0.5f, 0.5f);
|
|
subtitleRect.sizeDelta = new Vector2(2200f, 120f);
|
|
subtitleRect.anchoredPosition = new Vector2(0f, -60f);
|
|
}
|
|
|
|
if (_dimImage != null)
|
|
{
|
|
_dimImage.transform.SetAsFirstSibling();
|
|
}
|
|
|
|
if (_subtitleText != null)
|
|
{
|
|
_subtitleText.transform.SetAsLastSibling();
|
|
}
|
|
|
|
if (_titleText != null)
|
|
{
|
|
_titleText.transform.SetAsLastSibling();
|
|
}
|
|
}
|
|
|
|
private void ApplyContext(ChapterTitleFormContext context)
|
|
{
|
|
_hasPublishedCompletion = false;
|
|
ResetRuntimeTimings(context);
|
|
|
|
if (context == null)
|
|
{
|
|
_requestId = 0;
|
|
_chapterId = 0;
|
|
SetTitleText(string.Empty, string.Empty);
|
|
return;
|
|
}
|
|
|
|
_requestId = context.RequestId;
|
|
_chapterId = context.ChapterId;
|
|
|
|
string title = string.IsNullOrWhiteSpace(context.Title)
|
|
? BuildDefaultChapterTitle(_chapterId)
|
|
: context.Title.Trim();
|
|
string subtitle = string.IsNullOrWhiteSpace(context.Subtitle) ? string.Empty : context.Subtitle.Trim();
|
|
SetTitleText(title, subtitle);
|
|
}
|
|
|
|
private void SetTitleText(string title, string subtitle)
|
|
{
|
|
if (_titleText != null)
|
|
{
|
|
_titleText.text = title;
|
|
}
|
|
|
|
if (_subtitleText != null)
|
|
{
|
|
_subtitleText.text = subtitle;
|
|
_subtitleText.gameObject.SetActive(!string.IsNullOrEmpty(subtitle));
|
|
}
|
|
}
|
|
|
|
private void StartPlay()
|
|
{
|
|
StopPlay();
|
|
_playCoroutine = StartCoroutine(PlayRoutine());
|
|
}
|
|
|
|
private void StopPlay()
|
|
{
|
|
if (_playCoroutine == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StopCoroutine(_playCoroutine);
|
|
_playCoroutine = null;
|
|
}
|
|
|
|
private IEnumerator PlayRoutine()
|
|
{
|
|
SetDimAlpha(0f);
|
|
SetTitleAlpha(0f);
|
|
|
|
yield return FadeDimAlpha(0f, 1f, _runtimeDimFadeInDuration);
|
|
yield return WaitUnscaled(_runtimePreBlackDuration);
|
|
yield return WaitUnscaled(_runtimeTitleFadeInDelay);
|
|
yield return FadeTitleAlpha(0f, 1f, _runtimeTitleFadeInDuration);
|
|
yield return WaitUnscaled(_runtimeHoldDuration);
|
|
yield return FadeTitleAlpha(1f, 0f, _runtimeTitleFadeOutDuration);
|
|
yield return FadeDimAlpha(1f, 0f, _runtimeDimFadeOutDuration);
|
|
|
|
_playCoroutine = null;
|
|
|
|
PublishCompletionIfNeeded();
|
|
if (GameEntry.UI != null && UIForm != null)
|
|
{
|
|
GameEntry.UI.CloseUIForm(UIForm);
|
|
}
|
|
}
|
|
|
|
private IEnumerator FadeDimAlpha(float from, float to, float duration)
|
|
{
|
|
float safeDuration = Mathf.Max(0f, duration);
|
|
if (safeDuration <= 0f)
|
|
{
|
|
SetDimAlpha(to);
|
|
yield break;
|
|
}
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < safeDuration)
|
|
{
|
|
elapsed += Time.unscaledDeltaTime;
|
|
float t = Mathf.Clamp01(elapsed / safeDuration);
|
|
SetDimAlpha(Mathf.Lerp(from, to, t));
|
|
yield return null;
|
|
}
|
|
|
|
SetDimAlpha(to);
|
|
}
|
|
|
|
private IEnumerator FadeTitleAlpha(float from, float to, float duration)
|
|
{
|
|
float safeDuration = Mathf.Max(0f, duration);
|
|
if (safeDuration <= 0f)
|
|
{
|
|
SetTitleAlpha(to);
|
|
yield break;
|
|
}
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < safeDuration)
|
|
{
|
|
elapsed += Time.unscaledDeltaTime;
|
|
float t = Mathf.Clamp01(elapsed / safeDuration);
|
|
SetTitleAlpha(Mathf.Lerp(from, to, t));
|
|
yield return null;
|
|
}
|
|
|
|
SetTitleAlpha(to);
|
|
}
|
|
|
|
private static IEnumerator WaitUnscaled(float duration)
|
|
{
|
|
float safeDuration = Mathf.Max(0f, duration);
|
|
if (safeDuration <= 0f)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < safeDuration)
|
|
{
|
|
elapsed += Time.unscaledDeltaTime;
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
private void SetDimAlpha(float alpha)
|
|
{
|
|
if (_dimImage == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Color color = _dimImage.color;
|
|
color.a = Mathf.Clamp01(alpha);
|
|
_dimImage.color = color;
|
|
}
|
|
|
|
private void SetTitleAlpha(float alpha)
|
|
{
|
|
float clampedAlpha = Mathf.Clamp01(alpha);
|
|
SetTextAlpha(_titleText, clampedAlpha);
|
|
SetTextAlpha(_subtitleText, clampedAlpha);
|
|
}
|
|
|
|
private static void SetTextAlpha(TMP_Text text, float alpha)
|
|
{
|
|
if (text == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Color color = text.color;
|
|
color.a = alpha;
|
|
text.color = color;
|
|
}
|
|
|
|
private void ResetRuntimeTimings(ChapterTitleFormContext context)
|
|
{
|
|
_runtimeDimFadeInDuration = ResolveDuration(context != null ? context.DimFadeInDuration : -1f,
|
|
_dimFadeInDuration);
|
|
_runtimePreBlackDuration = ResolveDuration(context != null ? context.PreBlackDuration : -1f,
|
|
_preBlackDuration);
|
|
_runtimeTitleFadeInDelay = ResolveDuration(context != null ? context.TitleFadeInDelay : -1f,
|
|
_titleFadeInDelay);
|
|
_runtimeTitleFadeInDuration = ResolveDuration(context != null ? context.TitleFadeInDuration : -1f,
|
|
_fadeInDuration);
|
|
_runtimeHoldDuration = ResolveDuration(context != null ? context.HoldDuration : -1f, _holdDuration);
|
|
_runtimeTitleFadeOutDuration = ResolveDuration(context != null ? context.TitleFadeOutDuration : -1f,
|
|
_fadeOutDuration);
|
|
_runtimeDimFadeOutDuration = ResolveDuration(context != null ? context.DimFadeOutDuration : -1f,
|
|
_dimFadeOutDuration);
|
|
}
|
|
|
|
private static float ResolveDuration(float overrideDuration, float fallbackDuration)
|
|
{
|
|
return overrideDuration >= 0f ? overrideDuration : Mathf.Max(0f, fallbackDuration);
|
|
}
|
|
|
|
private void PublishCompletionIfNeeded()
|
|
{
|
|
if (_hasPublishedCompletion || _requestId <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_hasPublishedCompletion = true;
|
|
GameEntry.Event.Fire(this, ChapterTitleCompletedEventArgs.Create(_chapterId, _requestId));
|
|
}
|
|
|
|
private static string BuildDefaultChapterTitle(int chapterId)
|
|
{
|
|
return chapterId > 0 ? $"第{chapterId}章" : string.Empty;
|
|
}
|
|
|
|
private static CanvasGroup CreateContentGroup(RectTransform parent)
|
|
{
|
|
GameObject go = new GameObject("ContentRoot", typeof(RectTransform), typeof(CanvasGroup));
|
|
RectTransform rect = go.GetComponent<RectTransform>();
|
|
rect.SetParent(parent, false);
|
|
rect.anchorMin = Vector2.zero;
|
|
rect.anchorMax = Vector2.one;
|
|
rect.offsetMin = Vector2.zero;
|
|
rect.offsetMax = Vector2.zero;
|
|
return go.GetComponent<CanvasGroup>();
|
|
}
|
|
|
|
private static Image CreateImage(string name, RectTransform parent, Color color, bool raycastTarget)
|
|
{
|
|
GameObject go = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image));
|
|
RectTransform rect = go.GetComponent<RectTransform>();
|
|
rect.SetParent(parent, false);
|
|
rect.anchorMin = Vector2.zero;
|
|
rect.anchorMax = Vector2.one;
|
|
rect.offsetMin = Vector2.zero;
|
|
rect.offsetMax = Vector2.zero;
|
|
|
|
Image image = go.GetComponent<Image>();
|
|
image.color = color;
|
|
image.raycastTarget = raycastTarget;
|
|
return image;
|
|
}
|
|
|
|
private static TMP_Text CreateText(string name, RectTransform parent, float fontSize, FontStyles style,
|
|
TextAlignmentOptions alignment)
|
|
{
|
|
GameObject go = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI));
|
|
RectTransform rect = go.GetComponent<RectTransform>();
|
|
rect.SetParent(parent, false);
|
|
|
|
TextMeshProUGUI text = go.GetComponent<TextMeshProUGUI>();
|
|
if (TMP_Settings.defaultFontAsset != null)
|
|
{
|
|
text.font = TMP_Settings.defaultFontAsset;
|
|
}
|
|
|
|
text.text = string.Empty;
|
|
text.fontSize = fontSize;
|
|
text.fontStyle = style;
|
|
text.alignment = alignment;
|
|
text.color = new Color(0.96f, 0.94f, 0.88f, 1f);
|
|
text.raycastTarget = false;
|
|
return text;
|
|
}
|
|
}
|
|
}
|