using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System.Collections; public class readyLetsGo : MonoBehaviour { public List _321goImages; public GameObject _321goCanvasGO; public CanvasGroup _321goCanvasgroup; [Header("duration")] [SerializeField] float fadeInDuration; [SerializeField] float fadeOutDuration; [SerializeField] float displayDuration; public float oneImageDuration = 1f; public float waitingDuration = 0.25f; public float startScale = 1.25f; public float endScale = 0.8f; private Coroutine sequenceCoroutine; // Prevent re-entry / accidental double-play private bool isPlaying = false; private float lastPlayedTime = -10f; [Tooltip("Minimum seconds between automatic replays of the sequence")] public float replayCooldown = -9999f; // set to negative to prevent replays // Ensure the sequence only runs once per scene by default private bool playedOnce = false; private void Start() { // Ensure canvas is hidden initially if (_321goCanvasGO != null) { _321goCanvasGO.SetActive(false); } if (_321goCanvasgroup != null) { _321goCanvasgroup.alpha = 0; } // Ensure all images are inactive at start so they don't flash on scene load. if (_321goImages != null) { for (int i = 0; i < _321goImages.Count; i++) { var img = _321goImages[i]; if (img != null && img.gameObject.activeSelf) { img.gameObject.SetActive(false); } } } // reset play state on scene start isPlaying = false; lastPlayedTime = -10f; playedOnce = false; // allow one play when player initiates } /// /// Play the 3-2-1 GO sequence: fade in canvas, then cycle through images with fade in/out and scaling. /// Duration calculation: fadeInDuration = fadeOutDuration = oneImageDuration / 5, displayDuration = oneImageDuration * 3 / 5 /// public void PlaySequence() { // If already played once, do not play again if (playedOnce) return; // Prevent immediate replays or re-entrant calls if (isPlaying) { return; } if (Time.unscaledTime - lastPlayedTime < replayCooldown) { return; } // Stop any existing sequence if (sequenceCoroutine != null) { StopCoroutine(sequenceCoroutine); sequenceCoroutine = null; } // Calculate durations based on oneImageDuration fadeInDuration = oneImageDuration / 5f; fadeOutDuration = oneImageDuration / 5f; displayDuration = oneImageDuration * 3f / 5f; isPlaying = true; lastPlayedTime = Time.unscaledTime; sequenceCoroutine = StartCoroutine(PlaySequenceCoroutine()); } private IEnumerator PlaySequenceCoroutine() { // Activate canvas and fade in from alpha 0 to 1 over 0.25 seconds if (_321goCanvasGO != null) { _321goCanvasGO.SetActive(true); } if (_321goCanvasgroup != null) { float elapsedTime = 0f; while (elapsedTime < 0.25f) { elapsedTime += Time.unscaledDeltaTime; _321goCanvasgroup.alpha = Mathf.Clamp01(elapsedTime / 0.25f); yield return null; } _321goCanvasgroup.alpha = 1f; } // Wait for waitingDuration before starting the image sequence float waitElapsed = 0f; while (waitElapsed < waitingDuration) { waitElapsed += Time.unscaledDeltaTime; yield return null; } // Cycle through images in the list for (int i = 0; i < _321goImages.Count; i++) { Image currentImage = _321goImages[i]; if (currentImage == null) continue; // Start the fade in, display, and fade out sequence for this image yield return StartCoroutine(PlayImageSequence(currentImage)); // After the sequence finishes ensure the image is disabled (PlayImageSequence also disables, // but keep as defensive measure) try { if (currentImage != null) currentImage.gameObject.SetActive(false); } catch { } // If there's a next image, the next loop iteration will activate it when needed } // After all images done, hide canvas again if (_321goCanvasgroup != null) { // fade out canvas quickly float elapsed = 0f; float duration = 0.15f; float startA = _321goCanvasgroup.alpha; while (elapsed < duration) { elapsed += Time.unscaledDeltaTime; float frac = Mathf.Clamp01(elapsed / duration); _321goCanvasgroup.alpha = Mathf.Lerp(startA, 0f, frac); yield return null; } _321goCanvasgroup.alpha = 0f; } if (_321goCanvasGO != null) { _321goCanvasGO.SetActive(false); } sequenceCoroutine = null; // mark finished and record time isPlaying = false; lastPlayedTime = Time.unscaledTime; playedOnce = true; // ensure it won't run again unless ResetPlayState is called } private IEnumerator PlayImageSequence(Image image) { // Ensure the image GameObject is active only for the duration of its display try { if (!image.gameObject.activeSelf) image.gameObject.SetActive(true); } catch { } // Get the RectTransform for scaling RectTransform rectTransform = image.GetComponent(); if (rectTransform == null) { // If no rect, still wait whole duration then disable float fallbackTotal = fadeInDuration + displayDuration + fadeOutDuration; yield return new WaitForSecondsRealtime(fallbackTotal); try { image.gameObject.SetActive(false); } catch { } yield break; } // Initialize image alpha to 0 and scale to startScale Color imageColor = image.color; imageColor.a = 0f; image.color = imageColor; rectTransform.localScale = Vector3.one * startScale; float totalDuration = fadeInDuration + displayDuration + fadeOutDuration; float elapsedTime = 0f; while (elapsedTime < totalDuration) { elapsedTime += Time.unscaledDeltaTime; float normalizedTime = Mathf.Clamp01(elapsedTime / totalDuration); // Fade in phase (0 to fadeInDuration) if (elapsedTime < fadeInDuration) { float fadeInProgress = elapsedTime / Mathf.Max(0.0001f, fadeInDuration); imageColor.a = Mathf.Lerp(0f, 1f, fadeInProgress); } // Display phase (fadeInDuration to fadeInDuration + displayDuration) else if (elapsedTime < fadeInDuration + displayDuration) { imageColor.a = 1f; } // Fade out phase (fadeInDuration + displayDuration to total) else { float fadeOutProgress = (elapsedTime - fadeInDuration - displayDuration) / Mathf.Max(0.0001f, fadeOutDuration); imageColor.a = Mathf.Lerp(1f, 0f, fadeOutProgress); } // Apply alpha image.color = imageColor; // Continuous scaling from startScale to endScale throughout the entire sequence float currentScale = Mathf.Lerp(startScale, endScale, normalizedTime); rectTransform.localScale = Vector3.one * currentScale; yield return null; } // Ensure final state imageColor.a = 0f; image.color = imageColor; rectTransform.localScale = Vector3.one * endScale; // Disable the image GameObject after finished to avoid lingering in scene try { image.gameObject.SetActive(false); } catch { } } // Optional public reset if some external system wants to allow replay (e.g., scene reload) public void ResetPlayState() { isPlaying = false; lastPlayedTime = -10f; playedOnce = false; if (sequenceCoroutine != null) { try { StopCoroutine(sequenceCoroutine); } catch { } sequenceCoroutine = null; } } }