using System; using System.Collections; using BlueWater.Audios; using BlueWater.Interfaces; using BlueWater.Uis; using BlueWater.Utility; using Sirenix.OdinInspector; using UnityEngine; namespace BlueWater.Enemies.Bosses { public class BossHealthPoint : MonoBehaviour, IDamageable { // 컴포넌트 [Title("컴포넌트")] [SerializeField] private CapsuleCollider _characterCollider; [SerializeField] private Transform _particleInstantiateLocation; // 체력 설정 [field: Title("체력 설정")] [field: SerializeField] public int MaxHealthPoint { get; private set; } [field: SerializeField] public int CurrentHealthPoint { get; private set; } public bool IsInvincible { get; private set; } [field: SerializeField] public float InvincibilityDuration { get; private set; } = 0.1f; // 효과 설정 [Title("효과 설정")] [SerializeField] private string _attackedSfxName; [SerializeField] private string _dieSfxName; [SerializeField] private ParticleSystem _attackedParticle; [SerializeField] private ParticleSystem _dieParticle; private Material _materialInstance; private FieldBossHealthPointUi _fieldBossHealthPointUi; private WaitForSeconds _flashWhiteWaitTime; private Coroutine _flashWhiteCoroutine; private Coroutine _damageIntervalCoroutine; private bool _enableHealthChangedEvent; private string _bossName; // Hashes private static readonly int _isHitHash = Shader.PropertyToID("_IsHit"); // Events public event Action OnHealthChanged; public event Action OnDead; private void Awake() { InitializeComponent(); } // Unity events private void Start() { _flashWhiteWaitTime = new WaitForSeconds(InvincibilityDuration); _fieldBossHealthPointUi = CombatUiManager.Instance.FieldBossHealthPointUi; } private void OnDestroy() { if (!_enableHealthChangedEvent || !_fieldBossHealthPointUi) return; OnHealthChanged -= _fieldBossHealthPointUi.SetCurrentHealthPoint; } // Initialize methods [Button("셋팅 초기화")] private void InitializeComponent() { _characterCollider = GetComponent(); } public void Initialize(bool enableHealthChangedEvent, int maxHealthPoint, string bossName, Transform particleInstantiateLocation = null) { _enableHealthChangedEvent = enableHealthChangedEvent; MaxHealthPoint = maxHealthPoint; _bossName = bossName; _particleInstantiateLocation = particleInstantiateLocation; _fieldBossHealthPointUi ??= CombatUiManager.Instance.FieldBossHealthPointUi; if (_enableHealthChangedEvent) { OnHealthChanged += _fieldBossHealthPointUi.SetCurrentHealthPoint; _fieldBossHealthPointUi.SetBoss(MaxHealthPoint, _bossName); } SetCurrentHealthPoint(MaxHealthPoint); } // Methods public void SetCurrentHealthPoint(int changedHealthPoint) { CurrentHealthPoint = changedHealthPoint; OnHealthChanged?.Invoke(changedHealthPoint, _bossName); } public bool CanDamage() => !IsInvincible; public void TakeDamage(int damageAmount) { IsInvincible = true; var changeHp = Mathf.Max(CurrentHealthPoint - damageAmount, 0); SetCurrentHealthPoint(changeHp); Utils.StartUniqueCoroutine(this, ref _flashWhiteCoroutine, FlashWhiteCoroutine()); // if (_renderer.material.HasInt(_isHitHash)) // { // Utils.StartUniqueCoroutine(this, ref _flashWhiteCoroutine, FlashWhiteCoroutine()); // } // 죽었는지 체크 if (changeHp == 0) { Die(); return; } if (_attackedParticle) { var instantiateHitParticle = Instantiate(_attackedParticle, _characterCollider.bounds.center, _attackedParticle.transform.rotation, _particleInstantiateLocation); instantiateHitParticle.Play(); } if (!string.IsNullOrEmpty(_attackedSfxName)) { AudioManager.Instance.PlaySfx(_attackedSfxName); } Utils.StartUniqueCoroutine(this, ref _damageIntervalCoroutine, Utils.CoolDownCoroutine(InvincibilityDuration, EndDamageIntervalCoroutine)); } public void TryTakeDamage(int damageAmount) { if (!CanDamage()) return; TakeDamage(damageAmount); } public void Die() { if (_dieParticle) { var instantiateHitParticle = Instantiate(_dieParticle, _characterCollider.bounds.center, _dieParticle.transform.rotation, _particleInstantiateLocation); instantiateHitParticle.Play(); } if (!string.IsNullOrEmpty(_dieSfxName)) { AudioManager.Instance.PlaySfx(_dieSfxName); } OnDead?.Invoke(); } private IEnumerator FlashWhiteCoroutine() { _materialInstance.SetInt(_isHitHash, 1); yield return _flashWhiteWaitTime; _materialInstance.SetInt(_isHitHash, 0); Utils.EndUniqueCoroutine(this, ref _flashWhiteCoroutine); } private void EndDamageIntervalCoroutine() { IsInvincible = false; Utils.EndUniqueCoroutine(this, ref _damageIntervalCoroutine); } public void SetMaterialInstance(Material materialInstance) => _materialInstance = materialInstance; } }