185 lines
4.1 KiB
C#
185 lines
4.1 KiB
C#
|
using DG.Tweening;
|
||
|
using TMPro;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.UI;
|
||
|
|
||
|
namespace TPSBR.UI
|
||
|
{
|
||
|
public class UIHealth : UIBehaviour
|
||
|
{
|
||
|
// PRIVATE MEMBERS
|
||
|
|
||
|
[SerializeField]
|
||
|
private TextMeshProUGUI _healthText;
|
||
|
[SerializeField]
|
||
|
private Image _healthProgress;
|
||
|
[SerializeField]
|
||
|
private TextMeshProUGUI _maxHealthText;
|
||
|
[SerializeField]
|
||
|
private Image _healthIcon;
|
||
|
[SerializeField]
|
||
|
private Image _healthIcon2;
|
||
|
[SerializeField]
|
||
|
private float _healthAnimationDuration = 0.2f;
|
||
|
[SerializeField]
|
||
|
private Color[] _healthColors;
|
||
|
[SerializeField]
|
||
|
private Animation _criticalAnimation;
|
||
|
[SerializeField]
|
||
|
private float _criticalThreshold = 0.2f;
|
||
|
|
||
|
[SerializeField]
|
||
|
private Image _shieldIcon;
|
||
|
[SerializeField]
|
||
|
private TextMeshProUGUI _shieldText;
|
||
|
[SerializeField]
|
||
|
private Color _shieldInactiveColor = Color.gray;
|
||
|
[SerializeField]
|
||
|
private Image _shieldProgress;
|
||
|
[SerializeField]
|
||
|
private TextMeshProUGUI _maxShieldText;
|
||
|
|
||
|
private int _lastHealth = -1;
|
||
|
private int _lastMaxHealth = -1;
|
||
|
|
||
|
private int _lastShield = -1;
|
||
|
private int _lastMaxShield = -1;
|
||
|
|
||
|
private Health _health;
|
||
|
private Color _shieldColor;
|
||
|
|
||
|
// PUBLIC METHODS
|
||
|
|
||
|
public void UpdateHealth(Health health)
|
||
|
{
|
||
|
if (_health != health)
|
||
|
{
|
||
|
_health = health;
|
||
|
_lastHealth = -1;
|
||
|
_lastMaxHealth = -1;
|
||
|
_lastShield = -1;
|
||
|
_lastMaxShield = -1;
|
||
|
}
|
||
|
|
||
|
// HEALTH
|
||
|
|
||
|
int currentHealth = Mathf.RoundToInt(health.CurrentHealth);
|
||
|
|
||
|
if (currentHealth == 0 && health.CurrentHealth > 0)
|
||
|
{
|
||
|
// Do not show zero if not necessary
|
||
|
currentHealth = 1;
|
||
|
}
|
||
|
|
||
|
int maxHealth = (int)health.MaxHealth;
|
||
|
|
||
|
if (currentHealth != _lastHealth)
|
||
|
{
|
||
|
DOTween.Kill(_healthProgress);
|
||
|
|
||
|
float progress = currentHealth / health.MaxHealth;
|
||
|
_healthProgress.DOFillAmount(progress, _healthAnimationDuration);
|
||
|
|
||
|
_healthText.text = currentHealth.ToString();
|
||
|
|
||
|
UpdateHealthColor(health);
|
||
|
ShowCriticalAnimation(progress);
|
||
|
|
||
|
_lastHealth = currentHealth;
|
||
|
}
|
||
|
|
||
|
if (maxHealth != _lastMaxHealth)
|
||
|
{
|
||
|
if (_maxHealthText != null)
|
||
|
{
|
||
|
_maxHealthText.text = $"{maxHealth}";
|
||
|
}
|
||
|
|
||
|
_lastMaxHealth = maxHealth;
|
||
|
}
|
||
|
|
||
|
// SHIELD
|
||
|
|
||
|
int currentShield = (int)health.CurrentShield;
|
||
|
int maxShield = (int)health.MaxShield;
|
||
|
|
||
|
if (currentShield != _lastShield)
|
||
|
{
|
||
|
DOTween.Kill(_shieldProgress);
|
||
|
|
||
|
float progress = currentShield / health.MaxShield;
|
||
|
_shieldProgress.DOFillAmount(progress, _healthAnimationDuration);
|
||
|
|
||
|
_shieldText.text = currentShield.ToString();
|
||
|
_shieldText.color = currentShield > 0 ? _shieldColor : _shieldInactiveColor;
|
||
|
_shieldIcon.color = currentShield > 0 ? _shieldColor : _shieldInactiveColor;
|
||
|
|
||
|
UpdateHealthColor(health);
|
||
|
|
||
|
_lastShield = currentShield;
|
||
|
}
|
||
|
|
||
|
if (maxShield != _lastMaxShield)
|
||
|
{
|
||
|
if (_maxShieldText != null)
|
||
|
{
|
||
|
_maxShieldText.text = $"{maxShield}";
|
||
|
}
|
||
|
|
||
|
_lastMaxShield = maxShield;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MONOBEHAVIOUR
|
||
|
|
||
|
protected void Awake()
|
||
|
{
|
||
|
_shieldColor = _shieldIcon.color;
|
||
|
}
|
||
|
|
||
|
protected void OnEnable()
|
||
|
{
|
||
|
_criticalAnimation.SampleStart();
|
||
|
}
|
||
|
|
||
|
// PRIVATE MEMBERS
|
||
|
|
||
|
private void UpdateHealthColor(Health health)
|
||
|
{
|
||
|
var healthColor = GetHealthColor(health.CurrentHealth / health.MaxHealth);
|
||
|
_healthText.color = healthColor;
|
||
|
_healthIcon.color = healthColor;
|
||
|
_healthIcon2.color = healthColor;
|
||
|
_healthProgress.color = healthColor;
|
||
|
}
|
||
|
|
||
|
private Color GetHealthColor(float healthProgress)
|
||
|
{
|
||
|
float preciseIndex = MathUtility.Map(0f, 1f, 0f, _healthColors.Length - 1, healthProgress);
|
||
|
|
||
|
int fromIndex = (int)preciseIndex;
|
||
|
int toIndex = Mathf.Clamp(fromIndex + 1, 0, _healthColors.Length - 1);
|
||
|
|
||
|
return Color.Lerp(_healthColors[fromIndex], _healthColors[toIndex], preciseIndex - fromIndex);
|
||
|
}
|
||
|
|
||
|
private void ShowCriticalAnimation(float healthProgress)
|
||
|
{
|
||
|
if (healthProgress > _criticalThreshold)
|
||
|
{
|
||
|
if (_criticalAnimation.isPlaying == true)
|
||
|
{
|
||
|
_criticalAnimation.SampleStart();
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (_criticalAnimation.isPlaying == false)
|
||
|
{
|
||
|
_criticalAnimation.Play();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|