플레이어 HPBar
This commit is contained in:
160
Assets/02_Scripts/UI/PlayerHpBarUI.cs
Normal file
160
Assets/02_Scripts/UI/PlayerHpBarUI.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
// Screen-space HP bar for the player HUD.
|
||||
// Enemy HP bars can keep using the SpriteRenderer-based HpBar.
|
||||
public class PlayerHpBarUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Health _health;
|
||||
[SerializeField] private Image _fillImage;
|
||||
[SerializeField] private bool _autoFindPlayerHealth = true;
|
||||
[SerializeField] private bool _autoFindFillImageInChildren = true;
|
||||
[SerializeField] private bool _configureAsFilledImage = true;
|
||||
[SerializeField] private float _smoothSpeed = 0f;
|
||||
|
||||
[Header("Color Thresholds")]
|
||||
[SerializeField] private Color _highColor = new Color(0.2f, 0.9f, 0.3f, 1f);
|
||||
[SerializeField] private Color _midColor = new Color(1f, 0.85f, 0.2f, 1f);
|
||||
[SerializeField] private Color _lowColor = new Color(0.95f, 0.25f, 0.25f, 1f);
|
||||
[SerializeField, Range(0f, 1f)] private float _midThreshold = 0.5f;
|
||||
[SerializeField, Range(0f, 1f)] private float _lowThreshold = 0.2f;
|
||||
|
||||
private float _currentRatio = 1f;
|
||||
private float _targetRatio = 1f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
ResolveFillImage();
|
||||
ResolveHealth();
|
||||
ConfigureFillImage();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ResolveFillImage();
|
||||
ResolveHealth();
|
||||
ConfigureFillImage();
|
||||
|
||||
if (_health == null) return;
|
||||
|
||||
_health.OnHealthChanged += HandleHealthChanged;
|
||||
HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_health != null)
|
||||
_health.OnHealthChanged -= HandleHealthChanged;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
ResolveFillImage();
|
||||
ResolveHealth();
|
||||
ConfigureFillImage();
|
||||
|
||||
if (_health != null)
|
||||
HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_fillImage == null || _smoothSpeed <= 0f) return;
|
||||
if (Mathf.Approximately(_currentRatio, _targetRatio)) return;
|
||||
|
||||
_currentRatio = Mathf.MoveTowards(_currentRatio, _targetRatio, _smoothSpeed * Time.deltaTime);
|
||||
ApplyFill();
|
||||
}
|
||||
|
||||
public void Bind(Health health)
|
||||
{
|
||||
if (_health == health) return;
|
||||
|
||||
if (isActiveAndEnabled && _health != null)
|
||||
_health.OnHealthChanged -= HandleHealthChanged;
|
||||
|
||||
_health = health;
|
||||
|
||||
if (isActiveAndEnabled && _health != null)
|
||||
{
|
||||
_health.OnHealthChanged += HandleHealthChanged;
|
||||
HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleHealthChanged(int current, int max)
|
||||
{
|
||||
_targetRatio = max > 0 ? Mathf.Clamp01((float)current / max) : 0f;
|
||||
|
||||
if (_smoothSpeed <= 0f)
|
||||
{
|
||||
_currentRatio = _targetRatio;
|
||||
ApplyFill();
|
||||
}
|
||||
|
||||
ApplyColor(_targetRatio);
|
||||
}
|
||||
|
||||
private void ApplyFill()
|
||||
{
|
||||
if (_fillImage == null) return;
|
||||
_fillImage.fillAmount = Mathf.Clamp01(_currentRatio);
|
||||
}
|
||||
|
||||
private void ApplyColor(float ratio)
|
||||
{
|
||||
if (_fillImage == null) return;
|
||||
|
||||
if (ratio <= _lowThreshold)
|
||||
_fillImage.color = _lowColor;
|
||||
else if (ratio <= _midThreshold)
|
||||
_fillImage.color = _midColor;
|
||||
else
|
||||
_fillImage.color = _highColor;
|
||||
}
|
||||
|
||||
private void ResolveHealth()
|
||||
{
|
||||
if (_health != null || !_autoFindPlayerHealth) return;
|
||||
|
||||
PlayerController player = FindFirstObjectByType<PlayerController>();
|
||||
if (player != null)
|
||||
_health = player.GetComponent<Health>();
|
||||
}
|
||||
|
||||
private void ResolveFillImage()
|
||||
{
|
||||
if (_fillImage != null || !_autoFindFillImageInChildren) return;
|
||||
|
||||
Transform fill = FindChildByName(transform, "Fill");
|
||||
if (fill != null)
|
||||
_fillImage = fill.GetComponent<Image>();
|
||||
}
|
||||
|
||||
private Transform FindChildByName(Transform parent, string childName)
|
||||
{
|
||||
if (parent == null) return null;
|
||||
|
||||
for (int i = 0; i < parent.childCount; i++)
|
||||
{
|
||||
Transform child = parent.GetChild(i);
|
||||
if (child.name == childName)
|
||||
return child;
|
||||
|
||||
Transform nested = FindChildByName(child, childName);
|
||||
if (nested != null)
|
||||
return nested;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ConfigureFillImage()
|
||||
{
|
||||
if (_fillImage == null || !_configureAsFilledImage) return;
|
||||
|
||||
_fillImage.type = Image.Type.Filled;
|
||||
_fillImage.fillMethod = Image.FillMethod.Horizontal;
|
||||
_fillImage.fillOrigin = (int)Image.OriginHorizontal.Left;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/UI/PlayerHpBarUI.cs.meta
Normal file
2
Assets/02_Scripts/UI/PlayerHpBarUI.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ce8dd9c4b8941e2a69bbe4864891425
|
||||
Reference in New Issue
Block a user