using UnityEngine; using UnityEngine.UI; using DG.Tweening; using System.Collections.Generic; public class sliderProgressSc : MonoBehaviour { [Header("Slider Reference")] [SerializeField] private Slider targetSlider; [Header("Dots Configuration")] [SerializeField] private List dots = new List(); [SerializeField] private List dotImages = new List(); [Header("Slider Animation")] [SerializeField] private float sliderAnimationDuration = 0.8f; [SerializeField] private Ease sliderEase = Ease.OutCubic; [SerializeField] private bool animateSliderValue = true; [Header("Dot Animation Settings")] [SerializeField] private float scaleDuration = 0.3f; [SerializeField] private float colorDuration = 0.2f; [SerializeField] private Vector3 activeScale = Vector3.one * 1.2f; [SerializeField] private Vector3 inactiveScale = Vector3.one; [SerializeField] private Ease scaleEase = Ease.OutBack; [SerializeField] private float dotStaggerDelay = 0.05f; // Delay between dot activations [Header("Colors")] [SerializeField] private Color inactiveColor = new Color(0.3f, 0.3f, 0.3f, 0.6f); [SerializeField] private Color activeColor = new Color(0f, 1f, 0.4f, 1f); // Bright green [SerializeField] private Color pulseColor = new Color(1f, 1f, 0.4f, 1f); // Yellow pulse private float previousSliderValue; private int lastActivatedDot = -1; private Tween sliderTween; private bool isAnimating = false; void Start() { InitializeSlider(); SetupInitialState(); } void Update() { // Check if slider value changed if (Mathf.Abs(targetSlider.value - previousSliderValue) > 0.001f) { if (animateSliderValue && !isAnimating) { AnimateSliderToValue(targetSlider.value); } else { CheckAndAnimateDots(targetSlider.value); } previousSliderValue = targetSlider.value; } } void InitializeSlider() { if (targetSlider == null) targetSlider = GetComponent(); if (targetSlider == null) { Debug.LogError("No slider found! Please assign a slider reference."); return; } // Auto-populate dots if empty if (dots.Count == 0) { Debug.Log("No dots found! Please assign dot transforms manually."); } previousSliderValue = targetSlider.value; } void SetupInitialState() { // Set all dots to inactive state for (int i = 0; i < dots.Count; i++) { if (dots[i] != null) { dots[i].localScale = inactiveScale; if (i < dotImages.Count && dotImages[i] != null) { dotImages[i].color = inactiveColor; } } } lastActivatedDot = -1; } void AnimateSliderToValue(float targetValue) { if (sliderTween != null && sliderTween.IsActive()) { sliderTween.Kill(); } isAnimating = true; float startValue = targetSlider.value; sliderTween = DOTween.To(() => targetSlider.value, x => { targetSlider.value = x; CheckAndAnimateDots(x); }, targetValue, sliderAnimationDuration) .SetEase(sliderEase) .OnComplete(() => { isAnimating = false; }); } void CheckAndAnimateDots(float sliderValue) { // Calculate how many dots should be active based on slider value // For 10 dots: dot 0 at 0.1, dot 1 at 0.2, ..., dot 9 at 1.0 int dotsToActivate = Mathf.FloorToInt(sliderValue * dots.Count); // Clamp to valid range dotsToActivate = Mathf.Clamp(dotsToActivate, 0, dots.Count); // The actual active dot index (0-based, -1 means no dots active) int targetActiveDot = dotsToActivate - 1; // Check if we've moved forward to activate more dots if (targetActiveDot > lastActivatedDot) { // Activate dots with staggered delay for better visual effect for (int i = lastActivatedDot + 1; i <= targetActiveDot; i++) { if (i < dots.Count && i >= 0) { float delay = (i - (lastActivatedDot + 1)) * dotStaggerDelay; ActivateDotWithDelay(i, delay); } } lastActivatedDot = targetActiveDot; } // Check if we've moved backward (deactivate dots) else if (targetActiveDot < lastActivatedDot) { // Deactivate dots from lastActivatedDot down to targetActiveDot+1 for (int i = lastActivatedDot; i > targetActiveDot; i--) { if (i < dots.Count && i >= 0) { DeactivateDot(i); } } lastActivatedDot = targetActiveDot; } } void ActivateDotWithDelay(int dotIndex, float delay) { if (dotIndex >= dots.Count || dotIndex < 0 || dots[dotIndex] == null) return; DOVirtual.DelayedCall(delay, () => ActivateDot(dotIndex)); } void ActivateDot(int dotIndex) { if (dotIndex >= dots.Count || dotIndex < 0 || dots[dotIndex] == null) return; Transform dot = dots[dotIndex]; // Scale up animation with bounce effect dot.DOScale(activeScale, scaleDuration).SetEase(scaleEase); // Color change to active with pulse effect if (dotIndex < dotImages.Count && dotImages[dotIndex] != null) { Image dotImage = dotImages[dotIndex]; // Initial color change dotImage.DOColor(activeColor, colorDuration); // Add a subtle pulse effect dotImage.DOColor(pulseColor, colorDuration * 0.5f) .SetDelay(colorDuration) .SetLoops(2, LoopType.Yoyo) .SetEase(Ease.InOutSine); } } void DeactivateDot(int dotIndex) { if (dotIndex >= dots.Count || dotIndex < 0 || dots[dotIndex] == null) return; Transform dot = dots[dotIndex]; // Scale down animation dot.DOScale(inactiveScale, scaleDuration * 0.7f).SetEase(Ease.OutQuad); // Color change to inactive if (dotIndex < dotImages.Count && dotImages[dotIndex] != null) { dotImages[dotIndex].DOColor(inactiveColor, colorDuration * 0.7f); } } // Public methods for external control public void SetSliderValue(float value) { if (targetSlider != null) { if (animateSliderValue) { AnimateSliderToValue(value); } else { targetSlider.value = value; } } } public void SetSliderValueInstant(float value) { if (targetSlider != null) { targetSlider.value = value; CheckAndAnimateDots(value); } } public void ResetDots() { // Kill any running animations if (sliderTween != null && sliderTween.IsActive()) { sliderTween.Kill(); } for (int i = 0; i < dots.Count; i++) { if (dots[i] != null) { dots[i].DOKill(); } if (i < dotImages.Count && dotImages[i] != null) { dotImages[i].DOKill(); } } // Reset state lastActivatedDot = -1; isAnimating = false; SetupInitialState(); } // Get current progress (0-10) public int GetCurrentProgress() { return lastActivatedDot + 1; } // Check if specific dot is active public bool IsDotActive(int dotIndex) { return dotIndex <= lastActivatedDot; } void OnDestroy() { // Clean up any running tweens if (sliderTween != null && sliderTween.IsActive()) { sliderTween.Kill(); } for (int i = 0; i < dots.Count; i++) { if (dots[i] != null) { dots[i].DOKill(); } if (i < dotImages.Count && dotImages[i] != null) { dotImages[i].DOKill(); } } } // // Debug helper - shows current calculation values in inspector // [System.Serializable] // public class DebugInfo // { // [SerializeField] public float currentSliderValue; // [SerializeField] public int dotsToActivate; // [SerializeField] public int targetActiveDot; // [SerializeField] public int lastActivatedDot; // } // [Header("Debug Info (Runtime Only)")] // [SerializeField] private DebugInfo debugInfo = new DebugInfo(); // void LateUpdate() // { // // Update debug info for inspector visibility // if (targetSlider != null) // { // debugInfo.currentSliderValue = targetSlider.value; // debugInfo.dotsToActivate = Mathf.FloorToInt(targetSlider.value * dots.Count); // debugInfo.targetActiveDot = debugInfo.dotsToActivate - 1; // debugInfo.lastActivatedDot = lastActivatedDot; // } // } }