using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Contexts; using UnityEngine; using UnityEngine.Events; namespace BITKit.Entities { public interface IHealth { /// /// 当设置HP时的回调 /// public event Action OnSetHealthPoint; /// /// 当设置生存状态时的回调 /// public event Action OnSetAlive; /// /// 当受到伤害时的回调 /// public event Func OnDamageFactory; int HealthPoint { get; set; } int MaxHealthPoint { get; set; } bool IsAlive { get; } } [CustomType(typeof(IHealth))] public class EntityHealth : EntityBehavior, IHealth { [Header(Constant.Header.Settings)] [SerializeField] private int healthPoint = 100; [SerializeField] private int maxHealthPoint = 100; public event Action OnSetHealthPoint; public event Action OnSetAlive; public event Func OnDamageFactory; public int HealthPoint { get => healthPoint; set => OnHealthPointChangedInternal(healthPoint, value); } public int MaxHealthPoint { get => maxHealthPoint; set => maxHealthPoint = value; } public bool IsAlive { get; private set; } public override void OnAwake() { UnityEntity.AddListener(OnGetDamage); } public override void OnStart() { IsAlive = healthPoint >= 0; OnSetAliveInternal(IsAlive); OnHealthPointChangedInternal(0, healthPoint); } private void OnHealthPointChangedInternal(int old, int newHP) { healthPoint =Mathf.Clamp(newHP,-1,maxHealthPoint) ; var _isAlive = newHP >= 0; if (_isAlive != IsAlive) { OnSetAliveInternal(IsAlive = _isAlive); } OnSetHealthPoint?.Invoke(newHP); } private void OnSetAliveInternal(bool alive) { IsAlive = alive; OnSetAlive?.Invoke(alive); } private void AddHP(int hp) { OnHealthPointChangedInternal(healthPoint, healthPoint += hp); } private void OnGetDamage(DamageMessage damageMessage) { if (damageMessage.Target != UnityEntity) return; if (IsAlive is false) return; var damage = damageMessage.Damage; foreach (var x in OnDamageFactory.CastAsFunc().Reverse()) { damage = x.Invoke(damageMessage, damage); if (damage <= 0) break; } if (Data.Get("god") is false) AddHP(-damage); } #if UNITY_EDITOR [BIT] public void SetAlive() { BITAppForUnity.ThrowIfNotPlaying(); OnHealthPointChangedInternal(-1, 100); } [BIT] public void SetDead() { BITAppForUnity.ThrowIfNotPlaying(); OnHealthPointChangedInternal(100, -1); } #endif } }