플레이어 HPBar

This commit is contained in:
2026-05-20 13:05:49 +09:00
parent a0d04cf934
commit 57333a853e
6 changed files with 198 additions and 5 deletions

View 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;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0ce8dd9c4b8941e2a69bbe4864891425