using System; using System.Collections; using BlueWater.Audios; using BlueWater.Interfaces; using BlueWater.Uis; using BlueWater.Utility; using Sirenix.OdinInspector; using UnityEngine; namespace BlueWater.Players { public class PlayerHealthPoint : MonoBehaviour, IDamageable { // Components [SerializeField] private SpriteRenderer _spriteRenderer; private IDashable _dashable; private ISkillHandler _skillHandler; // Variables [field: SerializeField] public int MaxHealthPoint { get; private set; } [field: SerializeField] public int CurrentHealthPoint { get; private set; } [field: SerializeField] public float InvincibilityDuration { get; private set; } = 0.5f; [field: SerializeField] public bool IsInvincible { get; private set; } private WaitForSeconds _flashWhiteWaitTime; private Coroutine _flashWhiteCoroutine; private Coroutine _damageIntervalCoroutine; // Hashes private static readonly int IsHitHash = Shader.PropertyToID("_IsHit"); // Unity events private void Awake() { InitializeComponents(); } private void Start() { _flashWhiteWaitTime = new WaitForSeconds(InvincibilityDuration * 0.1f); SetCurrentHealthPoint(MaxHealthPoint); } // Initialize methods [Button("컴포넌트 초기화")] private void InitializeComponents() { _spriteRenderer = GetComponentInChildren(); _dashable = GetComponent(); _skillHandler = GetComponent(); } // Methods public void SetMaxHealthPoint(int changedHealthPoint) { var newChangedHealthPoint = Mathf.Clamp(changedHealthPoint, 0, 10); MaxHealthPoint = newChangedHealthPoint; EventManager.OnMaxHealthChanged?.Invoke(newChangedHealthPoint); } public void SetCurrentHealthPoint(int changedHealthPoint) { var newChangedHealthPoint = Mathf.Clamp(changedHealthPoint, 0, MaxHealthPoint); CurrentHealthPoint = newChangedHealthPoint; EventManager.OnHealthChanged?.Invoke(newChangedHealthPoint); if (CurrentHealthPoint <= 2) { PostProcessingManager.Instance.LowHpVignette(); } else { PostProcessingManager.Instance.DefaultHpVignette(); } } public bool CanDamage() { if (IsInvincible) return false; var isDashing = _dashable?.IsDashing ?? false; var isActivatingSkill = _skillHandler?.IsActivatingSkill ?? false; return !isDashing && !isActivatingSkill; } public void TakeDamage(int damageAmount) { IsInvincible = true; var changeHp = Mathf.Max(CurrentHealthPoint - damageAmount, 0); SetCurrentHealthPoint(changeHp); AudioManager.Instance.PlaySfx("CombatPlayerAttacked"); // 죽었는지 체크 if (changeHp == 0f) { Die(); return; } if (_spriteRenderer.material.HasInt(IsHitHash)) { Utils.StartUniqueCoroutine(this, ref _flashWhiteCoroutine, FlashWhiteCoroutine()); } Utils.StartUniqueCoroutine(this, ref _damageIntervalCoroutine, Utils.CoolDownCoroutine(InvincibilityDuration, EndDamageIntervalCoroutine)); } public void TryTakeDamage(int damageAmount) { if (!CanDamage()) return; TakeDamage(damageAmount); } public void Die() { EventManager.OnDead?.Invoke(); } private IEnumerator FlashWhiteCoroutine() { for (var i = 0; i < 5; i++) { _spriteRenderer.material.SetInt(IsHitHash, 1); yield return _flashWhiteWaitTime; _spriteRenderer.material.SetInt(IsHitHash, 0); yield return _flashWhiteWaitTime; } Utils.EndUniqueCoroutine(this, ref _flashWhiteCoroutine); } private void EndDamageIntervalCoroutine() { IsInvincible = false; Utils.EndUniqueCoroutine(this, ref _damageIntervalCoroutine); } public void ActivateInvincibility() => IsInvincible = true; public void DeactivateInvincibility() => IsInvincible = false; } }