using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Game;
using Music;
using Player;
namespace Player
{
[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; // Force applied when hit
///
/// The current accumulated damage of the player.
///
public float damage = 0f;
///
/// The maximum damage the player can take before dying.
///
public float maxDamage = 1000f; // Set max health
///
/// The number of lives the player has.
///
public int lives = 0;
private Animator animator;
///
/// 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 the player is punched.
///
public event System.Action OnPlayerPunched;
///
/// Event triggered when a player dies.
///
public event System.Action OnPlayerDeath;
///
/// Event triggered when a player respawns.
///
public event System.Action OnPlayerRespawn;
///
/// Unity Start method. Initializes the animator reference.
///
private void Start()
{
animator = GetComponent();
}
///
/// Unity Update method. Handles debug self-damage if enabled.
///
private void Update()
{
if (damageSelfDebug)
{
damageSelfDebug = false;
Damage(gameObject);
}
}
///
/// Unity OnTriggerEnter2D method. 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)
{
if (dying || damageSource.CompareTag("Hat")) return; // Exclude hat from taking damage
float actualForce = damageSource.GetComponent().force;
Block blockComponent = GetComponent();
GetComponentInChildren().DropItem(); // Drops hat if held
if (blockComponent != null && blockComponent.blocking)
{
if (blockComponent.IsParrying()) // Player receives damage if punching a parrying player
{
damageSource.GetComponent().SuccessfulParry(gameObject, actualForce);
AudioManager.Instance.PlaySound("Parry");
return;
}
else // Player does less damage if punching a blocking player
{
AudioManager.Instance.PlaySound("Punch");
actualForce /= 4;
GetComponent().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * actualForce, ForceMode2D.Force);
}
}
else // Player does full damage to a non-blocking player
{
AudioManager.Instance.PlaySound("Punch");
GetComponent().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * actualForce * (1 + (damage / maxDamage) * 3), ForceMode2D.Force);
}
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)
{
//if (GameManager.Instance.gameOver) return; // Prevent damage after game is over
this.damage += damage;
if (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) //&& !GameManager.Instance.gameOver) // Prevent death after game is over
{
UseItem useItem = GetComponent();
if (useItem != null)
{
useItem.DropItem(); // Ensure the player drops the item before the death animation
}
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;
if (TryGetComponent(out var rb))
{
rb.linearVelocity = Vector2.zero;
rb.angularVelocity = 0f;
}
if (TryGetComponent(out var damageable))
{
damageable.ResetDamage();
}
OnPlayerRespawn?.Invoke(gameObject);
}
///
/// Resets the player's damage to zero.
///
public void ResetDamage()
{
damage = 0f;
}
}
}