using TMPro; using UnityEngine; namespace RR.Common.UI { /// /// Компонент для создания анимированного сплеша текста. /// Поддерживает изменение размера, покачивание и изменение цвета. /// [RequireComponent(typeof(TextMeshProUGUI))] public class TextSplash : MonoBehaviour { [Header("Настройки масштаба")] [SerializeField] private bool animateScale = true; [SerializeField] private AnimationCurve scaleCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); [SerializeField] private float startScale = 0.5f; [SerializeField] private float endScale = 1.5f; [Header("Настройки покачивания")] [SerializeField] private bool animateSwing = true; [SerializeField] private float swingAmplitude = 20f; [SerializeField] private float swingFrequency = 2f; [SerializeField] private AnimationCurve swingCurve = AnimationCurve.EaseInOut(0, 0, 0.5f, 1); [Header("Настройки цвета")] [SerializeField] private bool animateColor = true; [SerializeField] private Gradient colorGradient = new Gradient(); [Header("Настройки движения")] [SerializeField] private bool animateMovement = true; [SerializeField] private Vector2 movementDirection = Vector2.up; [SerializeField] private float movementDistance = 100f; [SerializeField] private AnimationCurve movementCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); [Header("Общие настройки")] [SerializeField] private float animationDuration = 1f; [SerializeField] private bool loopAnimation = false; [SerializeField] private bool destroyOnComplete = true; private TextMeshProUGUI _textComponent; private RectTransform _rectTransform; private Vector2 _startPosition; private float _elapsed; private bool _isAnimating; private void Awake() { _textComponent = GetComponent(); _rectTransform = GetComponent(); _startPosition = _rectTransform.anchoredPosition; } private void OnEnable() { StartAnimation(); } /// /// Запускает анимацию сплеша /// public void StartAnimation() { _elapsed = 0f; _isAnimating = true; _startPosition = _rectTransform.anchoredPosition; } /// /// Устанавливает текст сплеша /// public void SetText(string text) { if (_textComponent != null) { _textComponent.text = text; } } /// /// Устанавливает начальный цвет /// public void SetColor(Color color) { if (_textComponent != null) { _textComponent.color = color; } } private void Update() { if (!_isAnimating) return; _elapsed += Time.unscaledDeltaTime; float t = Mathf.Clamp01(_elapsed / animationDuration); // Анимация масштаба if (animateScale) { float scaleValue = Mathf.Lerp(startScale, endScale, scaleCurve.Evaluate(t)); _rectTransform.localScale = Vector3.one * scaleValue; } // Анимация покачивания (rotation) if (animateSwing) { float swingValue = swingCurve.Evaluate(t) * swingAmplitude; // Используем частоту для создания непрерывного покачивания float swingAngle = Mathf.Sin(t * Mathf.PI * 2 * swingFrequency) * swingValue; _rectTransform.localRotation = Quaternion.Euler(0, 0, swingAngle); } // Анимация движения if (animateMovement) { float moveValue = movementCurve.Evaluate(t) * movementDistance; Vector2 offset = movementDirection.normalized * moveValue; _rectTransform.anchoredPosition = _startPosition + offset; } // Анимация цвета if (animateColor && _textComponent != null) { _textComponent.color = colorGradient.Evaluate(t); } // Завершение анимации if (t >= 1f) { if (loopAnimation) { // Перезапускаем анимацию с начала _elapsed = 0f; } else { _isAnimating = false; if (destroyOnComplete) { Destroy(gameObject); } } } } /// /// Устанавливает длительность анимации /// public void SetDuration(float duration) { animationDuration = duration; } /// /// Останавливает анимацию /// public void StopAnimation() { _isAnimating = false; } #if UNITY_EDITOR /// /// Предварительный просмотр в редакторе /// private void OnValidate() { if (colorGradient == null || colorGradient.colorKeys.Length == 0) { // Устанавливаем градиент по умолчанию (белый -> прозрачный) colorGradient = new Gradient(); colorGradient.SetKeys( new[] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, new[] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0f, 1f) } ); } } #endif } }