using System;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Colosseum.Enemy;
namespace Colosseum.UI
{
///
/// 보스 체력바 UI 컴포넌트.
/// BossEnemy의 체력 변화를 자동으로 UI에 반영합니다.
///
public class BossHealthBarUI : MonoBehaviour
{
[Header("References")]
[Tooltip("체력 슬라이더 (없으면 자동 검색)")]
[SerializeField] private Slider healthSlider;
[Tooltip("체력 텍스트 (예: '999 / 999')")]
[SerializeField] private TMP_Text healthText;
[Tooltip("보스 이름 텍스트")]
[SerializeField] private TMP_Text bossNameText;
[Header("Target")]
[Tooltip("추적할 보스 (런타임에 설정 가능)")]
[SerializeField] private BossEnemy targetBoss;
[Header("Settings")]
[Tooltip("보스 사망 시 UI 숨김 여부")]
[SerializeField] private bool hideOnDeath = true;
[Tooltip("슬라이더 값 변환 속도")]
[Min(0f)] [SerializeField] private float lerpSpeed = 5f;
private float displayHealthRatio;
private float targetHealthRatio;
private bool isSubscribed;
private bool isSubscribedToStaticEvent;
///
/// 현재 추적 중인 보스
///
public BossEnemy TargetBoss => targetBoss;
///
/// 보스 수동 설정 (런타임에서 호출)
///
public void SetBoss(BossEnemy boss)
{
// 기존 보스 이벤트 구독 해제
UnsubscribeFromBoss();
targetBoss = boss;
// 새 보스 이벤트 구독
SubscribeToBoss();
// 초기 UI 업데이트
if (targetBoss != null)
{
UpdateBossName();
UpdateHealthImmediate();
gameObject.SetActive(true);
}
else
{
gameObject.SetActive(false);
}
}
///
/// 보스 스폰 이벤트 핸들러
///
private void OnBossSpawned(BossEnemy boss)
{
if (boss == null)
return;
SetBoss(boss);
}
private void Awake()
{
// 컴포넌트 자동 검색
if (healthSlider == null)
healthSlider = GetComponentInChildren();
if (healthText == null)
healthText = transform.Find("SliderBox/Label_HP")?.GetComponent();
if (bossNameText == null)
bossNameText = transform.Find("SliderBox/Label_BossName")?.GetComponent();
}
private void OnEnable()
{
// 정적 이벤트 구독 (보스 스폰 자동 감지)
if (!isSubscribedToStaticEvent)
{
BossEnemy.OnBossSpawned += OnBossSpawned;
isSubscribedToStaticEvent = true;
}
}
private void OnDisable()
{
// 정적 이벤트 구독 해제
if (isSubscribedToStaticEvent)
{
BossEnemy.OnBossSpawned -= OnBossSpawned;
isSubscribedToStaticEvent = false;
}
}
private void Start()
{
// 이미 활성화된 보스가 있으면 연결
if (BossEnemy.ActiveBoss != null)
{
SetBoss(BossEnemy.ActiveBoss);
}
// 인스펙터에서 설정된 보스가 있으면 구독
else if (targetBoss != null)
{
SubscribeToBoss();
UpdateBossName();
UpdateHealthImmediate();
}
else
{
// 보스가 없으면 비활성화 (이벤트 대기)
gameObject.SetActive(false);
}
}
private void Update()
{
// 부드러운 체력바 애니메이션
if (!Mathf.Approximately(displayHealthRatio, targetHealthRatio))
{
displayHealthRatio = Mathf.Lerp(displayHealthRatio, targetHealthRatio, lerpSpeed * Time.deltaTime);
if (Mathf.Abs(displayHealthRatio - targetHealthRatio) < 0.01f)
displayHealthRatio = targetHealthRatio;
UpdateSliderVisual();
}
}
private void OnDestroy()
{
UnsubscribeFromBoss();
// 정적 이벤트 구독 해제
if (isSubscribedToStaticEvent)
{
BossEnemy.OnBossSpawned -= OnBossSpawned;
isSubscribedToStaticEvent = false;
}
}
private void SubscribeToBoss()
{
if (targetBoss == null || isSubscribed)
return;
targetBoss.OnHealthChanged += OnBossHealthChanged;
targetBoss.OnDeath += OnBossDeath;
isSubscribed = true;
}
private void UnsubscribeFromBoss()
{
if (targetBoss == null || !isSubscribed)
return;
targetBoss.OnHealthChanged -= OnBossHealthChanged;
targetBoss.OnDeath -= OnBossDeath;
isSubscribed = false;
}
private void OnBossHealthChanged(float currentHealth, float maxHealth)
{
if (maxHealth <= 0f)
return;
targetHealthRatio = Mathf.Clamp01(currentHealth / maxHealth);
UpdateHealthText(currentHealth, maxHealth);
}
private void OnBossDeath()
{
if (hideOnDeath)
{
gameObject.SetActive(false);
}
}
private void UpdateHealthImmediate()
{
if (targetBoss == null)
return;
float currentHealth = targetBoss.CurrentHealth;
float maxHealth = targetBoss.MaxHealth;
if (maxHealth <= 0f)
return;
targetHealthRatio = Mathf.Clamp01(currentHealth / maxHealth);
displayHealthRatio = targetHealthRatio;
UpdateSliderVisual();
UpdateHealthText(currentHealth, maxHealth);
}
private void UpdateSliderVisual()
{
if (healthSlider != null)
{
healthSlider.value = displayHealthRatio;
}
}
private void UpdateHealthText(float currentHealth, float maxHealth)
{
if (healthText != null)
{
healthText.text = $"{Mathf.CeilToInt(currentHealth)} / {Mathf.CeilToInt(maxHealth)}";
}
}
private void UpdateBossName()
{
if (bossNameText == null || targetBoss == null)
return;
// EnemyData에서 보스 이름 가져오기
if (targetBoss.Data != null && !string.IsNullOrEmpty(targetBoss.Data.EnemyName))
{
bossNameText.text = targetBoss.Data.EnemyName;
}
else
{
// 폴백: GameObject 이름 사용
bossNameText.text = targetBoss.name;
}
}
#if UNITY_EDITOR
private void OnValidate()
{
if (healthSlider == null)
healthSlider = GetComponentInChildren();
}
#endif
}
}