using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; public class VFXManager : MonoBehaviour { public static VFXManager Instance; private Transform camTransform; private Vector3 originalCamPos; private float originalTimeScale = 1f; private bool isSlowing = false; private Coroutine shakeCoroutine; private bool slowMoActive; private float slowMoTarget = 1f; private Dictionary wobbleCoroutines = new Dictionary(); private Dictionary originalUIPositions = new Dictionary(); public void StartWobble(RectTransform ui, float intensity, float speed) { if (ui == null) return; if (wobbleCoroutines.ContainsKey(ui)) StopCoroutine(wobbleCoroutines[ui]); if (!originalUIPositions.ContainsKey(ui)) originalUIPositions[ui] = ui.localPosition; wobbleCoroutines[ui] = StartCoroutine(WobbleLoop(ui, intensity, speed)); } public void StopWobble(RectTransform ui) { if (ui == null) return; if (wobbleCoroutines.ContainsKey(ui)) { StopCoroutine(wobbleCoroutines[ui]); wobbleCoroutines.Remove(ui); } if (originalUIPositions.ContainsKey(ui)) ui.localPosition = originalUIPositions[ui]; } private IEnumerator WobbleLoop(RectTransform ui, float intensity, float speed) { Vector3 basePos = originalUIPositions[ui]; float t = 0f; while (true) { t += Time.unscaledDeltaTime * speed; float x = Mathf.Sin(t * 1.2f) * intensity; float y = Mathf.Cos(t * 1.0f) * intensity; ui.localPosition = basePos + new Vector3(x, y, 0); yield return null; } } // ========================= // TEXT SYSTEM // ========================= private Dictionary breathingCoroutines = new Dictionary(); private Dictionary originalTextPositions = new Dictionary(); void Awake() { if (Instance == null) Instance = this; else { Destroy(gameObject); return; } camTransform = Camera.main.transform; originalCamPos = camTransform.localPosition; } // ========================= // CAMERA SHAKE // ========================= public void ScreenShake(float intensity, float duration) { if (shakeCoroutine != null) StopCoroutine(shakeCoroutine); shakeCoroutine = StartCoroutine(ShakeCoroutine(intensity, duration)); } private IEnumerator ShakeCoroutine(float intensity, float duration) { float elapsed = 0f; while (elapsed < duration) { Vector2 offset = Random.insideUnitCircle * intensity; camTransform.localPosition = originalCamPos + new Vector3(offset.x, offset.y, 0); elapsed += Time.unscaledDeltaTime; yield return null; } camTransform.localPosition = originalCamPos; shakeCoroutine = null; } // ========================= // SLOW MOTION // ========================= public void SlowMo(float ratio, float duration) { StartCoroutine(SlowMoRoutine(ratio, duration)); } private IEnumerator SlowMoRoutine(float ratio, float duration) { if (isSlowing) yield break; isSlowing = true; originalTimeScale = Time.timeScale; Time.timeScale = ratio; Time.fixedDeltaTime = 0.02f * Time.timeScale; yield return new WaitForSecondsRealtime(duration); Time.timeScale = originalTimeScale; Time.fixedDeltaTime = 0.02f; isSlowing = false; } // ========================= // TEXT SHAKE (ONE SHOT) // ========================= public void TextShake(TMP_Text text, float intensity, float duration) { StartCoroutine(TextShakeCoroutine(text, intensity, duration)); } private IEnumerator TextShakeCoroutine(TMP_Text text, float intensity, float duration) { if (!originalTextPositions.ContainsKey(text)) originalTextPositions[text] = text.rectTransform.localPosition; Vector3 basePos = originalTextPositions[text]; float elapsed = 0f; while (elapsed < duration) { Vector2 offset = Random.insideUnitCircle * intensity; text.rectTransform.localPosition = basePos + new Vector3(offset.x, offset.y, 0); elapsed += Time.unscaledDeltaTime; yield return null; } text.rectTransform.localPosition = basePos; } // ========================= // 🫁 BREATHING SYSTEM (NEW) // ========================= public void StartBreathing(TMP_Text text, float intensity) { if (breathingCoroutines.ContainsKey(text)) StopCoroutine(breathingCoroutines[text]); if (!originalTextPositions.ContainsKey(text)) originalTextPositions[text] = text.rectTransform.localPosition; breathingCoroutines[text] = StartCoroutine(BreathLoop(text, intensity)); } public void StopBreathing(TMP_Text text) { if (breathingCoroutines.ContainsKey(text)) { StopCoroutine(breathingCoroutines[text]); breathingCoroutines.Remove(text); } if (originalTextPositions.ContainsKey(text)) text.rectTransform.localPosition = originalTextPositions[text]; } private IEnumerator BreathLoop(TMP_Text text, float intensity) { Vector3 basePos = originalTextPositions[text]; float t = 0f; while (true) { t += Time.unscaledDeltaTime * 6f; float pulse = 1f + Mathf.Sin(t) * (0.05f + intensity * 0.01f); text.rectTransform.localPosition = basePos; text.rectTransform.localScale = Vector3.one * pulse; yield return null; } } public void SetSlowMo(float ratio) { slowMoActive = true; slowMoTarget = ratio; ApplySlowMo(); } public void StopSlowMo() { slowMoActive = false; Time.timeScale = 1f; Time.fixedDeltaTime = 0.02f; } private void ApplySlowMo() { Time.timeScale = slowMoTarget; Time.fixedDeltaTime = 0.02f * Time.timeScale; } }