El objetivo#
Un sistema de salud que puedas pegar a cualquier cosa (jugador, enemigo, caja rompible) y al que cualquier fuente de daño (espada, bala, trampa) pueda golpear sin conocer qué es. La clave: una interfaz y eventos.
Paso 1 — La interfaz IDañable#
public interface IDañable
{
void RecibirDaño(int cantidad);
}Cualquier clase que la implemente "promete" tener RecibirDaño. La espada no preguntará "¿eres un enemigo?", sino "¿eres IDañable?".
Paso 2 — El componente de vida#
using System;
using UnityEngine;
public class Salud : MonoBehaviour, IDañable
{
[SerializeField] private int vidaMax = 100;
public int VidaActual { get; private set; }
// Eventos para conectar UI, efectos, sonido... sin acoplar
public event Action<int, int> AlCambiar; // (actual, max)
public event Action AlMorir;
private bool muerto = false;
void Awake() => VidaActual = vidaMax;
public void RecibirDaño(int cantidad)
{
if (muerto) return;
VidaActual = Mathf.Clamp(VidaActual - cantidad, 0, vidaMax);
AlCambiar?.Invoke(VidaActual, vidaMax);
if (VidaActual == 0) Morir();
}
public void Curar(int cantidad)
{
if (muerto) return;
VidaActual = Mathf.Clamp(VidaActual + cantidad, 0, vidaMax);
AlCambiar?.Invoke(VidaActual, vidaMax);
}
void Morir()
{
muerto = true;
AlMorir?.Invoke(); // que cada quien reaccione (UI, drop, animación)
}
}Paso 3 — Hacer daño desde cualquier fuente#
Una bala o un raycast golpea sin saber qué toca:
void Impacto(Collider2D other)
{
if (other.TryGetComponent<IDañable>(out var objetivo))
objetivo.RecibirDaño(25);
}Mañana añades una PuertaReforzada o un Cristal que implementan IDañable, y la espada ya los daña sin tocar el código de la espada. Es el poder de programar contra un contrato en vez de contra tipos concretos. Ver herencia e interfaces.
Paso 4 — Conectar la UI (y todo lo demás)#
La barra de vida y cualquier otro sistema se suscriben a los eventos:
void OnEnable()
{
salud.AlCambiar += ActualizarBarra;
salud.AlMorir += MostrarGameOver;
}
void OnDisable()
{
salud.AlCambiar -= ActualizarBarra;
salud.AlMorir -= MostrarGameOver;
}El componente Salud no sabe que existe una barra, ni un game over, ni un sonido. Solo anuncia. Puedes enchufar y desenchufar reacciones libremente.
Extras habituales#
- Invulnerabilidad temporal tras recibir daño (i-frames): una bandera y un temporizador que ignora el daño unos instantes, con parpadeo del sprite.
- Knockback: aplicar un impulso al recibir daño (combina con Rigidbody).
- Tipos de daño (fuego, hielo) y resistencias, ampliando
RecibirDaño.
Errores frecuentes#
- Poner la vida como
public intque cualquiera modifica (usa métodos + propiedad de solo lectura). - Que cada enemigo tenga su propio código de vida distinto (unifica con el componente + interfaz).
- Que
Saludconozca la UI directamente (usa eventos). - No comprobar
muertoy dispararMorir()varias veces (drops duplicados, doble game over).
Resumen#
Un componente Salud que implementa IDañable y expone eventos (AlCambiar, AlMorir). Cualquier fuente de daño golpea con TryGetComponent<IDañable>() sin conocer el objetivo, y la barra de vida, los efectos y el game over se suscriben a los eventos. Reutilizable, desacoplado y ampliable a i-frames, knockback y tipos de daño.