Projext/Assets/02_Scripts/UI/HUD/HP Ui bar.cs
hydrozen e989d20668 카툰 쉐이더 추가 + 중복 스크립트 수정 + 전체 업데이트
- ToonPostProcess.shader: 횃불 고딕 스타일 후처리 쉐이더 (Built-in RP)
- ToonCameraEffect.cs: 카메라 자동 부착 후처리 스크립트
- 중복 UI 스크립트 제거 (MenuIntroController, ToggleCustom)
- 씬, 프리팹, 애니메이션 등 전체 업데이트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:31:16 +09:00

143 lines
7.3 KiB
C#

using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
using UnityEngine.UI; // UI 기능을 불러올거에요 -> UnityEngine.UI를
using TMPro; // TextMeshPro를 사용할거에요 -> TMPro를
/// <summary>
/// 플레이어 체력바 UI — PlayerHealth 이벤트 연동
/// HP_Filled (Image Fill) + Text (TMP) 실시간 갱신
/// </summary>
public class HPUibar : MonoBehaviour // 클래스를 선언할거에요 -> 체력바 UI를
{
[Header("--- 타겟 ---")] // 인스펙터 제목을 달거에요 -> 타겟 설정을
[SerializeField] private GameObject targetObject; // 변수를 선언할거에요 -> 타겟 오브젝트를 (Player)
[Header("--- UI 요소 ---")] // 인스펙터 제목을 달거에요 -> UI 요소를
[Tooltip("HP_Filled (Image, Fill 방식)")]
[SerializeField] private Image hpFilledImage; // 변수를 선언할거에요 -> 체력바 Fill 이미지를
[Tooltip("Text (TMP) — '현재HP / 최대HP' 표시")]
[SerializeField] private TextMeshProUGUI hpText; // 변수를 선언할거에요 -> 체력 텍스트를
// 캐싱된 참조
private PlayerHealth _playerHealth; // 변수를 선언할거에요 -> 플레이어 체력 스크립트를
private Stats _playerStats; // 변수를 선언할거에요 -> 플레이어 스탯 스크립트를
private void Awake() // 함수를 실행할거에요 -> 초기화 Awake를
{
if (targetObject != null) // 조건이 맞으면 실행할거에요 -> 타겟이 있다면
{
_playerHealth = targetObject.GetComponent<PlayerHealth>(); // 가져올거에요 -> PlayerHealth를
_playerStats = targetObject.GetComponent<Stats>(); // 가져올거에요 -> Stats를
}
}
private void OnEnable() // 함수를 실행할거에요 -> 활성화 시 OnEnable을
{
if (_playerHealth != null) // 조건이 맞으면 실행할거에요 -> 체력 스크립트가 있다면
{
_playerHealth.OnHealthChanged.AddListener(OnHealthRatioChanged); // 등록할거에요 -> 체력 변경 이벤트 리스너를
}
}
private void OnDisable() // 함수를 실행할거에요 -> 비활성화 시 OnDisable을
{
if (_playerHealth != null) // 조건이 맞으면 실행할거에요 -> 체력 스크립트가 있다면
{
_playerHealth.OnHealthChanged.RemoveListener(OnHealthRatioChanged); // 해제할거에요 -> 체력 변경 이벤트 리스너를
}
}
private void Start() // 함수를 실행할거에요 -> 시작 시 Start를
{
UpdateUI(); // 실행할거에요 -> 초기 UI 갱신을 (시작하자마자 올바른 값 표시)
}
/// <summary>
/// PlayerHealth.RefreshHealthUI()에서 ratio(0~1)를 받아 호출됨
/// </summary>
private void OnHealthRatioChanged(float ratio) // 함수를 선언할거에요 -> 체력 비율 변경 콜백을
{
// Fill Amount 갱신
if (hpFilledImage != null) // 조건이 맞으면 실행할거에요 -> Fill 이미지가 있다면
{
hpFilledImage.fillAmount = Mathf.Clamp01(ratio); // 값을 설정할거에요 -> 0~1 사이로 Fill Amount를
}
// 텍스트 갱신
UpdateHPText(); // 실행할거에요 -> 텍스트 갱신 함수를
}
/// <summary>
/// 텍스트를 "현재HP / 최대HP" 형식으로 갱신
/// </summary>
private void UpdateHPText() // 함수를 선언할거에요 -> HP 텍스트를 갱신하는 UpdateHPText를
{
if (hpText == null || _playerHealth == null || _playerStats == null) return; // 조건이 맞으면 중단할거에요 -> 필수 참조가 없으면
float current = _playerHealth.CurrentHP; // 값을 가져올거에요 -> 현재 체력을
float max = _playerStats.MaxHealth; // 값을 가져올거에요 -> 최대 체력을
hpText.text = $"{current:F0} / {max:F0}"; // 텍스트를 설정할거에요 -> "현재 / 최대" 형식으로
}
/// <summary>
/// 이벤트 없이 직접 UI를 갱신 (Start, 수동 호출용)
/// </summary>
private void UpdateUI() // 함수를 선언할거에요 -> 전체 UI 갱신을
{
if (_playerHealth == null || _playerStats == null) return; // 조건이 맞으면 중단할거에요 -> 참조가 없으면
float max = _playerStats.MaxHealth; // 값을 가져올거에요 -> 최대 체력을
float current = _playerHealth.CurrentHP; // 값을 가져올거에요 -> 현재 체력을
float ratio = (max > 0) ? current / max : 0f; // 비율을 계산할거에요 -> 현재/최대로
if (hpFilledImage != null) // 조건이 맞으면 실행할거에요 -> Fill 이미지가 있다면
{
hpFilledImage.fillAmount = Mathf.Clamp01(ratio); // 값을 설정할거에요 -> Fill Amount를
}
UpdateHPText(); // 실행할거에요 -> 텍스트 갱신을
}
// ─────────────────────────────────────────────────────────────
// 외부 연결 API (DungeonSceneSetup 폴백 모드용)
// ─────────────────────────────────────────────────────────────
/// <summary>
/// 런타임에서 타겟 오브젝트(플레이어)를 설정하고 컴포넌트를 재연결합니다.
/// DungeonSceneSetup의 폴백 모드에서 호출됩니다.
/// </summary>
public void SetTargetObject(GameObject newTarget) // 함수를 정의할거에요 -> 타겟 오브젝트 런타임 설정을
{
if (newTarget == null) return; // 방어할거에요 -> null이면 중단
// 기존 이벤트 해제 (중복 방지)
if (_playerHealth != null) // 조건이 맞으면 실행할거에요 -> 기존 연결이 있으면
{
_playerHealth.OnHealthChanged.RemoveListener(OnHealthRatioChanged); // 해제할거에요 -> 기존 리스너를
}
targetObject = newTarget; // 설정할거에요 -> 새 타겟 오브젝트를
_playerHealth = newTarget.GetComponent<PlayerHealth>(); // 가져올거에요 -> 새 타겟의 PlayerHealth를
_playerStats = newTarget.GetComponent<Stats>(); // 가져올거에요 -> 새 타겟의 Stats를
// 새 이벤트 등록
if (_playerHealth != null) // 조건이 맞으면 실행할거에요 -> 체력 스크립트가 있으면
{
_playerHealth.OnHealthChanged.AddListener(OnHealthRatioChanged); // 등록할거에요 -> 체력 변경 리스너를
}
UpdateUI(); // 실행할거에요 -> UI 즉시 갱신을
Debug.Log($"[HPUibar] 타겟 변경 완료: {newTarget.name}"); // 로그를 찍을거에요
}
/// <summary>
/// 외부에서 강제로 UI를 갱신합니다.
/// DungeonSceneSetup의 지연 갱신(DelayedUIRefresh)에서 호출됩니다.
/// 모든 Start()가 끝난 뒤 호출되므로 CurrentHP가 확실히 초기화된 상태입니다.
/// </summary>
public void ForceRefresh() // 함수를 정의할거에요 -> 강제 UI 갱신을
{
UpdateUI(); // 실행할거에요 -> Fill + 텍스트 전체 갱신을
Debug.Log("[HPUibar] ForceRefresh 완료"); // 로그를 찍을거에요
}
}