using System.Collections; using DG.Tweening; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.SceneManagement; using UnityEngine.UI; public class UI_CharacterDialogController : MonoBehaviour { [SerializeField] private string requiredSceneName = "UI_UI"; [SerializeField] private string characterObjectName = "Image_Character"; [SerializeField] private string dialogObjectName = "UI_DIALOG"; [Header("Enter")] [SerializeField] private float enterDuration = 0.3f; [SerializeField] private float enterFromOffsetY = 60f; [SerializeField] private Ease enterEase = Ease.OutCubic; [Header("Blink Out")] [SerializeField] private int blinkCount = 2; [SerializeField] private float blinkHalfTime = 0.05f; [Header("Auto Hide")] [SerializeField] private float idleHideDelay = 5f; [SerializeField] private bool useUnscaledTime = true; private RectTransform dialogRect; private CanvasGroup dialogGroup; private Vector2 dialogBasePos; private bool basePosCached; private RectTransform boundCharacterRect; private int bindAttemptToken; private bool isVisible; private Coroutine idleRoutine; private Coroutine bindRoutine; private Coroutine keepAliveRoutine; private Sequence dialogSequence; private UI_CharacterDialogClickProxy clickProxy; private Button characterButton; private bool initialHideDone; private void OnEnable() { SceneManager.sceneLoaded -= OnSceneLoaded; SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.activeSceneChanged -= OnActiveSceneChanged; SceneManager.activeSceneChanged += OnActiveSceneChanged; RebindSoon(); if (keepAliveRoutine == null) keepAliveRoutine = StartCoroutine(KeepBindingAliveRoutine()); } private void OnDisable() { SceneManager.sceneLoaded -= OnSceneLoaded; SceneManager.activeSceneChanged -= OnActiveSceneChanged; KillTweens(); if (characterButton != null) { characterButton.onClick.RemoveListener(OnCharacterClicked); characterButton = null; } if (idleRoutine != null) { StopCoroutine(idleRoutine); idleRoutine = null; } if (bindRoutine != null) { StopCoroutine(bindRoutine); bindRoutine = null; } if (keepAliveRoutine != null) { StopCoroutine(keepAliveRoutine); keepAliveRoutine = null; } clickProxy = null; dialogRect = null; dialogGroup = null; boundCharacterRect = null; basePosCached = false; initialHideDone = false; } public void RebindSoon() { bindAttemptToken++; if (bindRoutine != null) StopCoroutine(bindRoutine); bindRoutine = StartCoroutine(BindRoutine(bindAttemptToken)); } private IEnumerator BindRoutine(int token) { yield return null; TryBind(); yield return null; if (token != bindAttemptToken) yield break; yield return null; TryBind(); if (token != bindAttemptToken) yield break; yield return null; TryBind(); if (token != bindAttemptToken) yield break; yield return new WaitForSecondsRealtime(0.2f); TryBind(); if (token != bindAttemptToken) yield break; yield return new WaitForSecondsRealtime(0.6f); TryBind(); bindRoutine = null; } private void TryBind() { if (!IsAllowedScene()) return; Scene scene = gameObject.scene; if (!scene.IsValid() || !scene.isLoaded) scene = SceneManager.GetActiveScene(); Transform dialogTr = FindInSceneByName(scene, dialogObjectName); if (dialogTr == null) dialogTr = FindInSceneByName(SceneManager.GetActiveScene(), dialogObjectName); if (dialogTr != null) { RectTransform nextDialogRect = dialogTr as RectTransform; bool dialogChanged = dialogRect != nextDialogRect; dialogRect = nextDialogRect; if (dialogRect != null) { dialogGroup = dialogRect.GetComponent(); if (dialogGroup == null) dialogGroup = dialogRect.gameObject.AddComponent(); if (dialogChanged || !basePosCached) { dialogBasePos = dialogRect.anchoredPosition; basePosCached = true; } } if (!initialHideDone) { HideImmediate(); initialHideDone = true; } } Transform characterTr = FindInSceneByName(scene, characterObjectName); if (characterTr == null) characterTr = FindInSceneByName(SceneManager.GetActiveScene(), characterObjectName); if (characterTr != null) { boundCharacterRect = characterTr as RectTransform; clickProxy = characterTr.GetComponent(); if (clickProxy == null) clickProxy = characterTr.gameObject.AddComponent(); clickProxy.Bind(this); // Ensure the image can receive click events. Graphic graphic = characterTr.GetComponent(); if (graphic != null) graphic.raycastTarget = true; // Also bind through Button click to avoid missing pointer callbacks. Button btn = characterTr.GetComponent