using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class FishingUIEffects : MonoBehaviour { private readonly Dictionary runningEffects = new Dictionary(); private readonly Dictionary originalScales = new Dictionary(); private readonly Dictionary originalAnchoredPositions = new Dictionary(); public CanvasGroup EnsureCanvasGroup(GameObject target) { if (target == null) return null; CanvasGroup group = target.GetComponent(); if (group == null) group = target.AddComponent(); return group; } public void SetCanvasGroupInstant(GameObject target, CanvasGroup group, bool visible) { if (target == null && group == null) return; if (target != null) target.SetActive(visible); if (group != null) { group.alpha = visible ? 1f : 0f; group.interactable = visible; group.blocksRaycasts = visible; } } public void FadeCanvasGroup(GameObject target, CanvasGroup group, bool visible, float duration) { if (target == null && group == null) return; if (group == null && target != null) group = EnsureCanvasGroup(target); if (group == null) { if (target != null) target.SetActive(visible); return; } StopManaged(group); runningEffects[group] = StartCoroutine(FadeCanvasGroupRoutine(target, group, visible, Mathf.Max(0f, duration))); } private IEnumerator FadeCanvasGroupRoutine(GameObject target, CanvasGroup group, bool visible, float duration) { if (target != null && visible) target.SetActive(true); group.interactable = visible; group.blocksRaycasts = visible; float startAlpha = group.alpha; float endAlpha = visible ? 1f : 0f; if (duration <= 0f) { group.alpha = endAlpha; } else { float timer = 0f; while (timer < duration) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / duration); t = EaseOutCubic(t); group.alpha = Mathf.Lerp(startAlpha, endAlpha, t); yield return null; } group.alpha = endAlpha; } if (target != null && !visible) target.SetActive(false); runningEffects.Remove(group); } public void Pop(Transform target, float peakScale = 1.12f, float duration = 0.18f) { if (target == null) return; StopManaged(target); runningEffects[target] = StartCoroutine(PopRoutine(target, Mathf.Max(1f, peakScale), Mathf.Max(0.01f, duration))); } private IEnumerator PopRoutine(Transform target, float peakScale, float duration) { if (!originalScales.TryGetValue(target, out Vector3 originalScale)) { originalScale = target.localScale; originalScales[target] = originalScale; } float half = duration * 0.5f; float timer = 0f; while (timer < half) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / half); target.localScale = Vector3.Lerp(originalScale, originalScale * peakScale, EaseOutCubic(t)); yield return null; } timer = 0f; Vector3 peak = originalScale * peakScale; while (timer < half) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / half); target.localScale = Vector3.Lerp(peak, originalScale, EaseOutCubic(t)); yield return null; } target.localScale = originalScale; runningEffects.Remove(target); } public void Shake(RectTransform target, float strength = 12f, float duration = 0.18f) { if (target == null) return; StopManaged(target); runningEffects[target] = StartCoroutine(ShakeRoutine(target, Mathf.Max(0f, strength), Mathf.Max(0.01f, duration))); } private IEnumerator ShakeRoutine(RectTransform target, float strength, float duration) { if (!originalAnchoredPositions.TryGetValue(target, out Vector2 originalPosition)) { originalPosition = target.anchoredPosition; originalAnchoredPositions[target] = originalPosition; } float timer = 0f; while (timer < duration) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / duration); float power = Mathf.Lerp(strength, 0f, t); Vector2 offset = UnityEngine.Random.insideUnitCircle * power; target.anchoredPosition = originalPosition + offset; yield return null; } target.anchoredPosition = originalPosition; runningEffects.Remove(target); } public void Flash(Image image, Color color, float maxAlpha = 0.28f, float duration = 0.16f) { if (image == null) return; StopManaged(image); runningEffects[image] = StartCoroutine(FlashRoutine(image, color, Mathf.Clamp01(maxAlpha), Mathf.Max(0.01f, duration))); } private IEnumerator FlashRoutine(Image image, Color color, float maxAlpha, float duration) { image.gameObject.SetActive(true); image.raycastTarget = false; float timer = 0f; while (timer < duration) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / duration); Color current = color; current.a = Mathf.Lerp(maxAlpha, 0f, EaseOutCubic(t)); image.color = current; yield return null; } Color clear = color; clear.a = 0f; image.color = clear; image.gameObject.SetActive(false); runningEffects.Remove(image); } public void FillImage(Image image, float targetFill, float duration) { if (image == null) return; targetFill = Mathf.Clamp01(targetFill); StopManaged(image); runningEffects[image] = StartCoroutine(FillImageRoutine(image, targetFill, Mathf.Max(0f, duration))); } private IEnumerator FillImageRoutine(Image image, float targetFill, float duration) { float startFill = image.fillAmount; if (duration <= 0f) { image.fillAmount = targetFill; } else { float timer = 0f; while (timer < duration) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / duration); image.fillAmount = Mathf.Lerp(startFill, targetFill, EaseOutCubic(t)); yield return null; } image.fillAmount = targetFill; } runningEffects.Remove(image); } public void HighlightSlot(Image background, Image icon, Transform slotRoot, Color highlightColor, float duration, float popScale) { Object key = background != null ? background : icon != null ? icon : slotRoot; if (key == null) return; StopManaged(key); runningEffects[key] = StartCoroutine(HighlightSlotRoutine(background, icon, slotRoot, highlightColor, Mathf.Max(0.01f, duration), Mathf.Max(1f, popScale), key)); } private IEnumerator HighlightSlotRoutine(Image background, Image icon, Transform slotRoot, Color highlightColor, float duration, float popScale, Object key) { Color? originalBackground = null; Color? originalIcon = null; Vector3 originalScale = Vector3.one; if (background != null) { originalBackground = background.color; Color c = Color.Lerp(background.color, highlightColor, 0.65f); c.a = 1f; background.color = c; } if (icon != null) { originalIcon = icon.color; Color c = icon.color; c.a = 1f; icon.color = c; } if (slotRoot != null) { if (!originalScales.TryGetValue(slotRoot, out originalScale)) { originalScale = slotRoot.localScale; originalScales[slotRoot] = originalScale; } } float half = duration * 0.5f; float timer = 0f; while (timer < half) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / half); if (slotRoot != null) slotRoot.localScale = Vector3.Lerp(originalScale, originalScale * popScale, EaseOutCubic(t)); yield return null; } timer = 0f; Vector3 peak = originalScale * popScale; while (timer < half) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / half); if (slotRoot != null) slotRoot.localScale = Vector3.Lerp(peak, originalScale, EaseOutCubic(t)); if (background != null && originalBackground.HasValue) background.color = Color.Lerp(background.color, originalBackground.Value, t); if (icon != null && originalIcon.HasValue) icon.color = Color.Lerp(icon.color, originalIcon.Value, t); yield return null; } if (slotRoot != null) slotRoot.localScale = originalScale; if (background != null && originalBackground.HasValue) background.color = originalBackground.Value; if (icon != null && originalIcon.HasValue) icon.color = originalIcon.Value; runningEffects.Remove(key); } public void StopAllEffects() { foreach (Coroutine coroutine in runningEffects.Values) { if (coroutine != null) StopCoroutine(coroutine); } runningEffects.Clear(); foreach (KeyValuePair pair in originalScales) { if (pair.Key != null) pair.Key.localScale = pair.Value; } foreach (KeyValuePair pair in originalAnchoredPositions) { if (pair.Key != null) pair.Key.anchoredPosition = pair.Value; } } private void StopManaged(Object key) { if (key == null) return; if (runningEffects.TryGetValue(key, out Coroutine coroutine) && coroutine != null) StopCoroutine(coroutine); runningEffects.Remove(key); } private float EaseOutCubic(float t) { t = Mathf.Clamp01(t); t = 1f - Mathf.Pow(1f - t, 3f); return t; } }