using UnityEngine; using System; using System.Collections; using GameFramework; namespace IndianOceanAssets.Engine2_5D { // Handles health, damage, and death for entities public class HealthSystem : MonoBehaviour { /// 玩家受伤时触发(用于受击特效等) public static Action onPlayerDamaged; [Range(1, 100)] [SerializeField] private int maxHealth = 5; // Maximum health private int health = 5; // Current health [SerializeField] private GameObject deathEffect; // Effect prefab on death [SerializeField] private bool isPlayer; // Is this the player? [Header("消隐特效")] [Tooltip("死亡消隐使用的溶解材质(Custom/SpriteDissolve shader)")] [SerializeField] private Material dissolveMaterial; [Tooltip("消隐动画持续时间(秒)")] [SerializeField] private float fadeDuration = 2f; private bool _isDead = false; // 防止重复触发死亡 /// 是否已死亡(只读) public bool IsDead => _isDead; /// 最大血量(只读) public int MaxHealth => maxHealth; // Initializes health private void Start() { health = maxHealth; } // Applies damage and checks for death public void Damage(int damageAmount) { if (_isDead) return; // 已死亡,不再处理 health -= damageAmount; // 玩家受伤时触发事件(用于受击泛红特效) if (isPlayer && onPlayerDamaged != null) onPlayerDamaged.Invoke(); // 播放受伤音效 if (isPlayer && AudioManager.Instance != null) AudioManager.Instance.PlaySFXFromResources("SFX/Hurt", 0.7f); // If dead if (health <= 0) { _isDead = true; if (isPlayer) { // 玩家死亡:触发过场动画,不立即销毁(由 GameManager 处理) GameManager.GameOver(); } else { // 非玩家:正常播放死亡特效并销毁 Die(); } } } // Handles death logic and effects public void Die() { Debug.Log($"[HealthSystem] Die() called on {gameObject.name}, dissolveMaterial={(dissolveMaterial != null ? dissolveMaterial.name : "NULL")}"); if (deathEffect != null) Instantiate(deathEffect, transform.position + new Vector3(0f, .5f, 0f), Quaternion.identity); // 如果有溶解材质,播放消隐动画后再销毁 if (dissolveMaterial != null) { Debug.Log($"[HealthSystem] Starting DissolveAndDestroy coroutine on {gameObject.name}"); StartCoroutine(DissolveAndDestroy()); } else { Debug.Log($"[HealthSystem] No dissolve material, destroying {gameObject.name} immediately"); Destroy(gameObject); } } /// /// 溶解消隐协程:切换材质 → 禁用碰撞/AI → 动画溶解 → 销毁。 /// private IEnumerator DissolveAndDestroy() { Debug.Log($"[HealthSystem] DissolveAndDestroy START on {gameObject.name}"); // 禁用碰撞体和刚体,防止死亡过程中仍能触发碰撞或受重力下坠 foreach (var col in GetComponents()) col.enabled = false; foreach (var col in GetComponents()) col.enabled = false; foreach (var rb in GetComponents()) rb.isKinematic = true; foreach (var rb in GetComponents()) rb.isKinematic = true; // 禁用所有 MonoBehaviour(AI、动画等),防止死亡后仍移动/攻击 foreach (var mb in GetComponents()) { if (mb != this) mb.enabled = false; } // 等一帧,确保禁用生效 yield return null; // 切换所有 SpriteRenderer 到溶解材质(保留原始纹理和颜色) var renderers = GetComponentsInChildren(); Debug.Log($"[HealthSystem] DissolveAndDestroy: {renderers.Length} SpriteRenderers on {gameObject.name}"); for (int i = 0; i < renderers.Length; i++) { // 创建溶解材质实例,并复制原始纹理 + 颜色 var dissolveMat = new Material(dissolveMaterial); if (renderers[i].sprite != null) dissolveMat.mainTexture = renderers[i].sprite.texture; dissolveMat.SetColor("_Color", renderers[i].color); dissolveMat.SetFloat("_DissolveAmount", 0f); renderers[i].material = dissolveMat; } // 再等一帧,确保材质切换生效 yield return null; Debug.Log($"[HealthSystem] Starting dissolve animation, fadeDuration={fadeDuration}"); // 动画溶解 float elapsed = 0f; while (elapsed < fadeDuration) { elapsed += Time.deltaTime; float t = Mathf.Clamp01(elapsed / fadeDuration); for (int i = 0; i < renderers.Length; i++) { if (renderers[i] != null && renderers[i].material != null) renderers[i].material.SetFloat("_DissolveAmount", t); } yield return null; } Debug.Log($"[HealthSystem] Dissolve complete, destroying {gameObject.name}"); Destroy(gameObject); } } }