114 lines
4.3 KiB
C#
114 lines
4.3 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using Cysharp.Threading.Tasks;
|
||
using System.Threading;
|
||
|
||
public class HealthSegmentedView : MonoBehaviour
|
||
{
|
||
[SerializeField] private List<GameObject> 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<GameObject> newDamagedSegments = new List<GameObject>();
|
||
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;
|
||
}
|
||
} |