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);
}
}
}