Files
Crash-Course/Assets/Scripts/Player/Damageable.cs

237 lines
7.7 KiB
C#
Raw Normal View History

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