using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; [SerializeField] public class Damageable : IDamageable { public event Action OnTakeDamage; public event Action OnDeath; public event Action OnHeal; [SerializeField] public int BaseHealth { get; protected set; } public int CurrentHealth { get; protected set; } public bool IsDead => CurrentHealth <= 0; public bool IsInvincible => Time.time < InvincibleUntil; public float InvincibleUntil { get; protected set; } = 0f; public float InvincibilityLeft => Math.Max(0, InvincibleUntil - Time.time); [SerializeField] public float InvincibilityDuration { get; protected set; } = 0; public bool IsFrameFrozen => Time.time < FrameFrozenUntil; public float FrameFrozenUntil { get; protected set; } public float FrameFreezeLeft => Math.Max(0, FrameFrozenUntil - Time.time); [SerializeField] public float FrameFreezeDuration { get; protected set; } = 0; public int DamageTaken { get; protected set; } public Vector2 DirectionOfDamage { get; protected set; } [SerializeField] public bool IsKnockable { get; protected set; } public int Knockback { get; protected set; } public void Damage(int amount, Vector2 hitDirection, int knockback = 1) { if (IsDead || IsInvincible) return; CurrentHealth -= amount; CurrentHealth = Mathf.Max(CurrentHealth, 0); InvincibleUntil = Time.time + InvincibilityDuration; FrameFrozenUntil = Time.time + FrameFreezeDuration; DamageTaken = amount; if (IsKnockable) Knockback = knockback; hitDirection = hitDirection.normalized; if (hitDirection == Vector2.zero) hitDirection = Vector2.up; DirectionOfDamage = hitDirection; OnTakeDamage?.Invoke(amount, hitDirection); if (CurrentHealth == 0) OnDeath?.Invoke(); } public void Heal(int amount) { if (IsDead) return; CurrentHealth += amount; CurrentHealth = Mathf.Min(CurrentHealth, BaseHealth); OnHeal?.Invoke(amount); } public void Reset() { CurrentHealth = BaseHealth; InvincibleUntil = Time.time; FrameFrozenUntil = Time.time; } } public interface IDamageable { int BaseHealth { get; } int CurrentHealth { get; } bool IsDead { get; } bool IsInvincible { get; } float InvincibleUntil { get; } float InvincibilityLeft { get; } float InvincibilityDuration { get; } bool IsFrameFrozen { get; } float FrameFrozenUntil { get; } float FrameFreezeLeft { get; } float FrameFreezeDuration { get; } int DamageTaken { get; } Vector2 DirectionOfDamage { get; } bool IsKnockable { get; } int Knockback { get; } public void Damage(int amount, Vector2 hitDirection, int knockback = 1); public void Heal(int amount); public void Reset(); }