Что я не так делаю с интерфейсами?
Всё.
У тебя у одного интерфейса слишком много ответственностей у него и Warside какой-то есть и дамаг может принимать и умереть может.
Разделяй этот интерфейс на несколько.
namespace Health
{
public interface IHealth
{
void Lose(int amount);
void Restore(int amount);
}
public interface IMutable<out T>
{
T Current { get; }
}
public interface IFinal
{
event Action Over;
}
}
Получается такой Health:
using System;
using UnityEngine;
namespace Health
{
public class Health : IHealth, IFinal, IMutable<int>
{
public event Action Over;
private readonly int _max;
private const int Min = 0;
public Health(int max)
{
_max = max;
Current = _max;
}
public int Current { get; private set; }
public void Lose(int amount)
{
SetCurrent(Current - amount);
}
public void Restore(int amount)
{
SetCurrent(Current + amount);
}
private void SetCurrent(int amount)
{
Current = Mathf.Clamp(amount, Min, _max);
if (Current == Min) Over?.Invoke();
}
}
}
Health не должен быть отдельным компонентом, который будет висеть на условном рыцаре. Рыцарь будет содержать в себе этот Health, но напрямую хп ему изменять никто не будет, поэтому нужен еще один интерфейс IDamageable:
namespace Health
{
public interface IDamageable
{
void ApplyDamage(int amount);
}
}
И сам рыцарь:
using UnityEngine;
namespace Health
{
public class Knight : MonoBehaviour, IDamageable
{
[SerializeField] private int _maxHealth = 100;
private Health _health;
private void Awake()
{
_health = new Health(_maxHealth);
}
private void OnEnable()
{
_health.Over += Die;
}
private void OnDisable()
{
_health.Over -= Die;
}
public void ApplyDamage(int amount)
{
_health.Lose(amount);
Debug.Log($"Damaged, hp left - {_health.Current}");
}
private void Die()
{
Debug.Log("Died");
Destroy(gameObject);
}
}
}
Теперь, чтобы нанести урон рыцарю, нужно получить компонент IDamageable и вызвать его метод ApplyDamage:
using UnityEngine;
namespace Health
{
public class Enemy : MonoBehaviour
{
[SerializeField] private int _damage = 50;
private void OnTriggerEnter2D(Collider2D other)
{
if (other.TryGetComponent(out IDamageable damageable))
{
damageable.ApplyDamage(_damage);
}
}
}
}
Всё. Используй TryGetComponent и тогда не нужно будет делать миллион проверок является ли что-то null.
Warside твой должен висеть на рыцаре, а не на хп, поэтому делай отдельный интерфейс под этот Warside.