93 lines
7.8 KiB
C#
93 lines
7.8 KiB
C#
using UnityEngine; // 유니티 기본 기능(카메라, Mathf 등)을 쓰기 위해 불러올거에요 -> UnityEngine를
|
|
using UnityEngine.UI; // Image 컴포넌트를 쓰기 위해 불러올거에요 -> UnityEngine.UI를
|
|
using TMPro; // TextMeshProUGUI를 쓰기 위해 불러올거에요 -> TMPro를
|
|
|
|
public class HPUibar : MonoBehaviour // 클래스를 선언할거에요 -> 체력바 UI를 갱신하는 HPUibar를
|
|
{ // 코드 블록을 시작할거에요 -> HPUibar 범위를
|
|
|
|
[Header("--- 참조 ---")] // 인스펙터에 제목을 표시할거에요 -> 참조 섹션을
|
|
[SerializeField] private MonoBehaviour healthSource; // 변수를 선언할거에요 -> 체력 소스(플레이어/몹 등)를 healthSource에
|
|
|
|
[Header("--- UI ---")] // 인스펙터에 제목을 표시할거에요 -> UI 섹션을
|
|
[SerializeField] private Image hpFillImage; // 변수를 선언할거에요 -> 체력 게이지 채움(Image.fillAmount)용 hpFillImage를
|
|
[SerializeField] private TextMeshProUGUI hpText; // 변수를 선언할거에요 -> 체력 텍스트 표시용 hpText를
|
|
|
|
private PlayerHealth _playerHealth; // 변수를 선언할거에요 -> PlayerHealth를 캐싱할 _playerHealth를
|
|
private Stats _playerStats; // 변수를 선언할거에요 -> PlayerHealth의 Stats를 캐싱할 _playerStats를
|
|
|
|
private void Start() // 함수를 선언할거에요 -> 시작 시 1회 실행되는 Start를
|
|
{ // 코드 블록을 시작할거에요 -> Start 범위를
|
|
|
|
// ✅ PlayerHealth는 UnityEvent<float> (ratio만 줌)이므로 AddListener 방식으로 구독할거에요 -> UnityEvent 전용 처리
|
|
if (healthSource is PlayerHealth ph) // 조건을 검사할거에요 -> healthSource가 PlayerHealth인지
|
|
{ // 코드 블록을 시작할거에요 -> PlayerHealth 처리 범위를
|
|
_playerHealth = ph; // 값을 저장할거에요 -> PlayerHealth 캐싱
|
|
_playerStats = ph.GetComponent<Stats>(); // 컴포넌트를 가져올거에요 -> 같은 오브젝트의 Stats를 캐싱
|
|
ph.OnHealthChanged.AddListener(UpdateUIFromRatio); // 이벤트를 구독할거에요 -> UnityEvent<float>라 AddListener 사용
|
|
ForceRefreshPlayerUI(); // 시작 시 UI를 강제로 한 번 맞출거에요 -> CurrentHP 기반으로
|
|
} // 코드 블록을 끝낼거에요 -> PlayerHealth 처리
|
|
|
|
// ✅ 나머지는 (current,max) Action 이벤트라 기존처럼 += 구독할거에요 -> 기존 코드 유지
|
|
else if (healthSource is TrainingDummy td) td.OnHealthChanged += UpdateUI; // 더미면 (current,max) 이벤트 구독할거에요 -> UpdateUI로
|
|
else if (healthSource is EnemyHealth eh) eh.OnHealthChanged += UpdateUI; // 적이면 (current,max) 이벤트 구독할거에요 -> UpdateUI로
|
|
else if (healthSource is MonsterClass mc) mc.OnHealthChanged += UpdateUI; // 몬스터면 (current,max) 이벤트 구독할거에요 -> UpdateUI로
|
|
|
|
if (hpFillImage != null) hpFillImage.fillAmount = 1f; // 조건이 맞으면 실행할거에요 -> 시작 시 게이지를 풀로 표시
|
|
} // 코드 블록을 끝낼거에요 -> Start를
|
|
|
|
private void ForceRefreshPlayerUI() // 함수를 선언할거에요 -> PlayerHealth용 UI 강제 갱신 함수 ForceRefreshPlayerUI를
|
|
{ // 코드 블록을 시작할거에요 -> ForceRefreshPlayerUI 범위를
|
|
if (_playerHealth == null) return; // 조건이 맞으면 중단할거에요 -> 플레이어가 없으면
|
|
float max = (_playerStats != null) ? _playerStats.MaxHealth : 0f; // 값을 구할거에요 -> Stats가 있으면 MaxHealth를, 없으면 0을
|
|
UpdateUI(_playerHealth.CurrentHP, max); // 함수를 실행할거에요 -> current/max 형태로 UI를 통일해서 갱신
|
|
} // 코드 블록을 끝낼거에요 -> ForceRefreshPlayerUI를
|
|
|
|
private void UpdateUIFromRatio(float ratio) // 함수를 선언할거에요 -> PlayerHealth(UnityEvent<float>)가 보내는 ratio를 받는 UpdateUIFromRatio를
|
|
{ // 코드 블록을 시작할거에요 -> UpdateUIFromRatio 범위를
|
|
ratio = Mathf.Clamp01(ratio); // 값을 보정할거에요 -> ratio를 0~1로 고정
|
|
if (hpFillImage != null) hpFillImage.fillAmount = ratio; // 조건이 맞으면 실행할거에요 -> 게이지를 ratio만큼 채우기
|
|
|
|
// 텍스트는 ratio만으론 current/max를 모름 -> PlayerHealth/Stats에서 직접 읽어서 찍을거에요 -> 코드 영향 최소
|
|
if (_playerHealth != null && hpText != null) // 조건을 검사할거에요 -> PlayerHealth와 텍스트가 있는지
|
|
{ // 코드 블록을 시작할거에요 -> 텍스트 갱신 범위를
|
|
float max = (_playerStats != null) ? _playerStats.MaxHealth : 0f; // 값을 구할거에요 -> Stats가 있으면 MaxHealth를
|
|
float cur = _playerHealth.CurrentHP; // 값을 구할거에요 -> PlayerHealth의 현재 체력을
|
|
hpText.text = (max > 0f) // 조건을 검사할거에요 -> max가 0보다 큰지
|
|
? $"{Mathf.CeilToInt(cur)} / {Mathf.CeilToInt(max)}" // 조건이 맞으면 실행할거에요 -> current/max로 표시
|
|
: $"{Mathf.RoundToInt(ratio * 100f)}%"; // 조건이 틀리면 실행할거에요 -> max를 못 구하면 퍼센트로 표시
|
|
} // 코드 블록을 끝낼거에요 -> 텍스트 갱신
|
|
} // 코드 블록을 끝낼거에요 -> UpdateUIFromRatio를
|
|
|
|
private void UpdateUI(float current, float max) // 함수를 선언할거에요 -> (current,max) 이벤트용 UI 갱신 함수 UpdateUI를
|
|
{ // 코드 블록을 시작할거에요 -> UpdateUI 범위를
|
|
if (hpFillImage != null && max > 0f) // 조건을 검사할거에요 -> 이미지가 있고 max가 0보다 큰지
|
|
{ // 코드 블록을 시작할거에요 -> 게이지 갱신 범위를
|
|
hpFillImage.fillAmount = current / max; // 값을 넣을거에요 -> 체력 비율로 게이지 채우기
|
|
} // 코드 블록을 끝낼거에요 -> 게이지 갱신
|
|
|
|
if (hpText != null) // 조건을 검사할거에요 -> 텍스트가 있는지
|
|
{ // 코드 블록을 시작할거에요 -> 텍스트 갱신 범위를
|
|
hpText.text = $"{Mathf.CeilToInt(current)} / {Mathf.CeilToInt(max)}"; // 값을 넣을거에요 -> current/max 텍스트 표시
|
|
} // 코드 블록을 끝낼거에요 -> 텍스트 갱신
|
|
} // 코드 블록을 끝낼거에요 -> UpdateUI를
|
|
|
|
private void LateUpdate() // 함수를 선언할거에요 -> 모든 Update 후 실행되는 LateUpdate를
|
|
{ // 코드 블록을 시작할거에요 -> LateUpdate 범위를
|
|
if (Camera.main != null) // 조건을 검사할거에요 -> 메인 카메라가 있는지
|
|
transform.LookAt(transform.position + Camera.main.transform.forward); // 회전을 맞출거에요 -> 카메라 전방을 바라보게(빌보드)
|
|
} // 코드 블록을 끝낼거에요 -> LateUpdate를
|
|
|
|
private void OnDestroy() // 함수를 선언할거에요 -> 오브젝트가 파괴될 때 호출되는 OnDestroy를
|
|
{ // 코드 블록을 시작할거에요 -> OnDestroy 범위를
|
|
|
|
// ✅ PlayerHealth는 UnityEvent라 RemoveListener로 해제할거에요 -> 누수 방지
|
|
if (_playerHealth != null) _playerHealth.OnHealthChanged.RemoveListener(UpdateUIFromRatio); // 조건이 맞으면 실행할거에요 -> UnityEvent 구독 해제
|
|
|
|
// ✅ 나머지는 Action 이벤트라 기존처럼 -= 해제할거에요 -> 기존 코드 유지
|
|
if (healthSource is TrainingDummy td) td.OnHealthChanged -= UpdateUI; // 더미면 구독 해제할거에요 -> UpdateUI를
|
|
else if (healthSource is EnemyHealth eh) eh.OnHealthChanged -= UpdateUI; // 적이면 구독 해제할거에요 -> UpdateUI를
|
|
else if (healthSource is MonsterClass mc) mc.OnHealthChanged -= UpdateUI; // 몬스터면 구독 해제할거에요 -> UpdateUI를
|
|
|
|
} // 코드 블록을 끝낼거에요 -> OnDestroy를
|
|
|
|
} // 코드 블록을 끝낼거에요 -> HPUibar를 |