using System.Collections.Generic; using UnityEngine; using Cysharp.Threading.Tasks; using System.Threading; public class HealthSegmentedView : MonoBehaviour { [SerializeField] private List segments; [Header("Blink Settings")] [SerializeField] private float blinkInterval = 0.1f; // Интервал между миганиями [SerializeField] private int blinkCount = 3; // Количество миганий private Health playerHealth; private int lastDamagedCount = -1; // Количество поврежденных сегментов private CancellationTokenSource cancellationTokenSource; public void Initialize() { playerHealth = G.PlayerStateModel.PlayerHealthComponent; playerHealth.HealthChanged += Refresh; Refresh(-1); } void Refresh(float healthChanged) { int newDamagedCount = CalculateDamagedSegmentsCount(); // Если количество поврежденных сегментов увеличилось (получили урон) if (newDamagedCount > lastDamagedCount && lastDamagedCount != -1) { int newlyDamagedCount = newDamagedCount - lastDamagedCount; // Новые поврежденные сегменты - это те, что находятся в диапазоне [lastDamagedCount, newDamagedCount) BlinkNewlyDamagedSegments(lastDamagedCount, newlyDamagedCount).Forget(); } // Обновляем отображение for (int i = 0; i < segments.Count; i++) { bool shouldBeActive = i < newDamagedCount; // Активны = повреждены (показывают урон) segments[i].SetActive(shouldBeActive); } lastDamagedCount = newDamagedCount; } private int CalculateDamagedSegmentsCount() { return (int)((float)segments.Count * (1 - playerHealth.HpPercent)); } private async UniTaskVoid BlinkNewlyDamagedSegments(int startIndex, int count) { // Отменяем предыдущее мигание cancellationTokenSource?.Cancel(); cancellationTokenSource = new CancellationTokenSource(); var token = cancellationTokenSource.Token; // Получаем новые поврежденные сегменты List newDamagedSegments = new List(); for (int i = startIndex; i < startIndex + count && i < segments.Count; i++) { newDamagedSegments.Add(segments[i]); } // Они уже должны быть активны (повреждены), но мы будем мигать для визуального эффекта // Мигаем указанное количество раз for (int i = 0; i < blinkCount; i++) { if (token.IsCancellationRequested) break; // Выключаем сегменты (как будто они восстанавливаются) foreach (var segment in newDamagedSegments) { if (segment != null) segment.SetActive(false); } await UniTask.Delay((int)(blinkInterval * 1000), cancellationToken: token); if (token.IsCancellationRequested) break; // Включаем обратно (показываем повреждение) foreach (var segment in newDamagedSegments) { if (segment != null) segment.SetActive(true); } await UniTask.Delay((int)(blinkInterval * 1000), cancellationToken: token); } // В конце мигания УБЕЖДАЕМСЯ, что сегменты включены (повреждены) if (!token.IsCancellationRequested) { foreach (var segment in newDamagedSegments) { if (segment != null) segment.SetActive(true); // Оставляем включенными - они показывают полученный урон } } } private void OnDestroy() { cancellationTokenSource?.Cancel(); cancellationTokenSource?.Dispose(); if (playerHealth != null) playerHealth.HealthChanged -= Refresh; } }