using System.Collections; using System.Collections.Generic; using UnityEngine; using Game; using Music; using Player; namespace Player { /// /// This class handles the player's ability to take damage, die, and respawn. /// It also manages interactions like blocking, parrying, and dropping items when hit. /// [RequireComponent(typeof(Rigidbody2D))] [RequireComponent(typeof(Collider2D))] [RequireComponent(typeof(RespawnOnTriggerEnter))] public class Damageable : MonoBehaviour { /// /// The force applied to the player when hit. /// public float force = 50f; /// /// The current accumulated damage of the player. /// public float damage = 0f; /// /// The maximum damage the player can take before dying. /// public float maxDamage = 1000f; /// /// The number of lives the player has. /// public int lives = 0; /// /// If true, applies damage to self for debugging purposes. /// public bool damageSelfDebug = false; /// /// Indicates whether the player is currently dying. /// public bool dying = false; /// /// Event triggered when a player dies. /// public event System.Action OnPlayerDeath; /// /// Event triggered when a player respawns. /// public event System.Action OnPlayerRespawn; /// /// Reference to the player's animator component. /// private Animator animator; /// /// Initializes the animator reference. /// private void Start() { animator = GetComponent(); } /// /// Handles debug self-damage if enabled. /// private void Update() { if (damageSelfDebug) { damageSelfDebug = false; Damage(gameObject); } } /// /// Applies damage when colliding with a punch hurtbox. /// /// The collider that entered the trigger. private void OnTriggerEnter2D(Collider2D collision) { if (collision.gameObject.CompareTag("Punch Hurtbox")) { Damage(collision.transform.parent.gameObject); } } /// /// Applies damage to the player from a given damage source. /// Handles blocking, parrying, and force application. /// /// The GameObject causing the damage. private void Damage(GameObject damageSource) { // Prevent damage if the player is dying or the damage source is a hat if (dying || damageSource.CompareTag("Hat")) return; float actualForce = damageSource.GetComponent().force; Block blockComponent = GetComponent(); // Drop the item if the player is holding one GetComponentInChildren().DropItem(); if (blockComponent != null && blockComponent.blocking) { if (blockComponent.IsParrying()) { // Handle parry logic damageSource.GetComponent().SuccessfulParry(gameObject, actualForce); AudioManager.Instance.PlaySound("Parry"); return; } else { // Reduce damage if the player is blocking AudioManager.Instance.PlaySound("Punch"); actualForce /= 4; GetComponent().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * actualForce, ForceMode2D.Force); } } else { // Apply full damage if the player is not blocking AudioManager.Instance.PlaySound("Punch"); GetComponent().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * actualForce * (1 + (damage / maxDamage) * 3), ForceMode2D.Force); } // Update the player's damage and check if they should die damage += actualForce; damage = Mathf.Clamp(damage, 0f, maxDamage); if (damage >= maxDamage) { Die(); } } /// /// Adds a specified amount of damage to the player. /// /// The amount of damage to add. public void Damage(float damage) { this.damage += damage; if (this.damage >= maxDamage) { Die(); } } /// /// Handles the effects of a successful parry, applying force and damage. /// /// The GameObject that was parried. /// The force to apply. private void SuccessfulParry(GameObject damageSource, float force) { GetComponent().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * force, ForceMode2D.Force); damage += force; damage = Mathf.Clamp(damage, 0f, maxDamage); if (damage >= maxDamage) { Die(); } } /// /// Triggers the death animation and sets the player to the dying state. /// private void Die() { if (GameManager.Instance != null) { // Drop the item if the player is holding one UseItem useItem = GetComponent(); if (useItem != null) { useItem.DropItem(); } // Trigger the death animation and mark the player as dying animator.SetBool("die", true); dying = true; AudioManager.Instance.PlaySound("Death Simple"); OnPlayerDeath?.Invoke(gameObject); } } /// /// Handles player state after death and resets dying state after respawn. /// public void HandleDeath() { print("Player " + gameObject.name + " died"); GameManager.Instance.PlayerDied(this); animator.SetBool("die", false); dying = false; } /// /// Respawns the player at the spawn position and resets damage/health bar. /// public void Respawn() { //transform.position = GameManager.Instance.spawnPosition; // Reset the player's velocity if (TryGetComponent(out var rb)) { rb.linearVelocity = Vector2.zero; rb.angularVelocity = 0f; } // Reset the player's damage ResetDamage(); OnPlayerRespawn?.Invoke(gameObject); } /// /// Resets the player's damage to zero. /// public void ResetDamage() { damage = 0f; } } }