using System.Collections;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
using UnityEngine.Localization.Components;
using UnityEngine.UI;
namespace AibisDream.MiniGame.Language
{
///
/// Drives the full-frame Huoshan expression screen while keeping readable text in TMP.
/// The sprite sheet uses the original 384x216 Aseprite timing and the existing world-space
/// Canvas remains the source of truth for interaction and dynamic language particles.
///
public sealed class ExpressionScreenPresentationController : MonoBehaviour
{
public enum ScreenState
{
Reset,
Deep,
Panel,
Output,
Floating,
Click,
FocusHidden
}
private const int DeepFirst = 0;
private const int DeepLast = 14;
private const int UiFlashFirst = 15;
private const int UiFlashLast = 29;
private const int StatusRevealFrame = 21;
private const int RingFirst = 30;
private const int RingLast = 40;
private const int OutputFirst = 41;
private const int OutputLast = 47;
private const int OutputTextRevealFrame = 45;
private const int FloatingFrame = 48;
private const int ClickFirst = 49;
private const int ClickLast = 52;
private const string ObjectiveLocalizationKey = "huoshan_expression_objective";
private const string OutputLocalizationKey = "huoshan_expression_output";
[Header("Frame Animation")]
[SerializeField] private SpriteRenderer screenRenderer;
[SerializeField] private Sprite[] frames = new Sprite[53];
[SerializeField] private Vector3 screenLocalPosition = new Vector3(0.68f, -8.95f, 0f);
[SerializeField] private Vector3 screenLocalScale = new Vector3(1.1f, 1.1f, 1f);
[Header("Existing TMP / Interaction")]
[SerializeField] private TMP_Text integrationProgressText;
[SerializeField] private TMP_Text interferenceCountText;
[SerializeField] private Button outputButton;
[SerializeField] private TMP_FontAsset screenFont;
[Header("Status TMP (screen-space world units)")]
[SerializeField] private Vector2 integrationStatusPosition = new Vector2(-8.75f, 4.15f);
[SerializeField] private Vector2 interferenceStatusPosition = new Vector2(-8.75f, 3.08f);
[SerializeField] private Vector2 statusPanelSize = new Vector2(4.55f, 0.6f);
[SerializeField] private Vector4 statusTextMargins = new Vector4(0.16f, 0.05f, 0.08f, 0.05f);
[SerializeField] private float statusFontSize = 0.26f;
[SerializeField] private Color screenTextColor = new Color(0.78f, 0.91f, 1f, 1f);
[Header("Output Button Hit Area")]
[SerializeField] private Vector2 outputButtonPosition = new Vector2(4.86f, -0.065f);
[SerializeField] private Vector2 outputButtonSize = new Vector2(2.72f, 1.13f);
[Header("Objective TMP (384x216 reference)")]
[SerializeField] private Vector2 objectivePosition = new Vector2(-8.18f, -4.08f);
[SerializeField] private Vector2 objectiveSize = new Vector2(7.4f, 0.95f);
[SerializeField] private float objectiveFontSize = 0.28f;
[SerializeField] private Color objectiveColor = new Color(0.78f, 0.91f, 1f, 1f);
private int playbackGeneration;
private TMP_Text objectiveText;
private TMP_Text outputText;
private LocalizeStringEvent objectiveLocalization;
private LocalizeStringEvent outputLocalization;
private Material objectiveMaterial;
private ScreenState state = ScreenState.Reset;
public ScreenState State => state;
private void Awake()
{
ResolveSceneReferences();
ConfigureExistingUiAsTextOnly();
CreateObjectiveText();
BindStaticLocalization();
ResetImmediate();
}
private void ResolveSceneReferences()
{
if (screenRenderer == null)
{
SpriteRenderer[] renderers = GetComponentsInChildren(true);
foreach (SpriteRenderer candidate in renderers)
{
if (candidate != null && candidate.gameObject.name == "火山释放log界面")
{
screenRenderer = candidate;
break;
}
}
}
if (outputButton != null)
{
outputText = outputButton.GetComponentInChildren(true);
}
if (screenRenderer != null)
{
screenRenderer.transform.localPosition = screenLocalPosition;
screenRenderer.transform.localScale = screenLocalScale;
}
}
private void ConfigureExistingUiAsTextOnly()
{
MakeParentImageTransparent(integrationProgressText);
MakeParentImageTransparent(interferenceCountText);
ConfigureStatusText(integrationProgressText, integrationStatusPosition);
ConfigureStatusText(interferenceCountText, interferenceStatusPosition);
ConfigureOutputText();
if (outputButton != null && outputButton.targetGraphic != null)
{
Color color = outputButton.targetGraphic.color;
color.a = 0f;
outputButton.targetGraphic.color = color;
outputButton.targetGraphic.raycastTarget = true;
}
}
private void ConfigureStatusText(TMP_Text text, Vector2 panelPosition)
{
if (text == null)
return;
if (screenFont != null)
text.font = screenFont;
text.fontSize = statusFontSize;
text.fontStyle = FontStyles.Normal;
text.color = screenTextColor;
text.alignment = TextAlignmentOptions.MidlineLeft;
text.enableWordWrapping = false;
text.overflowMode = TextOverflowModes.Truncate;
text.margin = statusTextMargins;
text.raycastTarget = false;
if (text.transform.parent is RectTransform panelRect)
{
panelRect.anchorMin = new Vector2(0.5f, 0.5f);
panelRect.anchorMax = new Vector2(0.5f, 0.5f);
panelRect.pivot = new Vector2(0f, 0.5f);
panelRect.anchoredPosition = panelPosition;
panelRect.sizeDelta = statusPanelSize;
}
RectTransform textRect = text.rectTransform;
textRect.anchorMin = Vector2.zero;
textRect.anchorMax = Vector2.one;
textRect.pivot = new Vector2(0.5f, 0.5f);
textRect.anchoredPosition = Vector2.zero;
textRect.sizeDelta = Vector2.zero;
}
private void ConfigureOutputText()
{
if (outputButton == null)
return;
RectTransform buttonRect = outputButton.transform as RectTransform;
if (buttonRect != null)
{
buttonRect.anchorMin = new Vector2(0.5f, 0.5f);
buttonRect.anchorMax = new Vector2(0.5f, 0.5f);
buttonRect.pivot = new Vector2(0f, 0.5f);
buttonRect.anchoredPosition = outputButtonPosition;
buttonRect.sizeDelta = outputButtonSize;
}
if (outputText == null)
return;
if (screenFont != null)
outputText.font = screenFont;
outputText.fontStyle = FontStyles.Normal;
outputText.color = screenTextColor;
outputText.alignment = TextAlignmentOptions.Center;
outputText.enableWordWrapping = false;
outputText.overflowMode = TextOverflowModes.Truncate;
RectTransform textRect = outputText.rectTransform;
textRect.anchorMin = Vector2.zero;
textRect.anchorMax = Vector2.one;
textRect.pivot = new Vector2(0.5f, 0.5f);
textRect.anchoredPosition = Vector2.zero;
textRect.sizeDelta = Vector2.zero;
}
private static void MakeParentImageTransparent(TMP_Text text)
{
if (text == null || text.transform.parent == null)
return;
Image image = text.transform.parent.GetComponent();
if (image == null)
return;
Color color = image.color;
color.a = 0f;
image.color = color;
image.raycastTarget = false;
}
private void CreateObjectiveText()
{
Canvas canvas = integrationProgressText != null
? integrationProgressText.GetComponentInParent