Files
gold_dolphin/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs
T
2026-07-05 15:33:41 +08:00

145 lines
4.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using System;
using System.Collections;
using GameFramework;
namespace IndianOceanAssets.Engine2_5D
{
// Handles health, damage, and death for entities
public class HealthSystem : MonoBehaviour
{
/// <summary>玩家受伤时触发(用于受击特效等)</summary>
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; // 防止重复触发死亡
/// <summary>是否已死亡(只读)</summary>
public bool IsDead => _isDead;
/// <summary>最大血量(只读)</summary>
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()
{
if (deathEffect != null)
Instantiate(deathEffect, transform.position + new Vector3(0f, .5f, 0f), Quaternion.identity);
// 如果有溶解材质,播放消隐动画后再销毁
if (dissolveMaterial != null)
{
StartCoroutine(DissolveAndDestroy());
}
else
{
Destroy(gameObject);
}
}
/// <summary>
/// 溶解消隐协程:切换材质 → 禁用碰撞/AI → 动画溶解 → 销毁。
/// </summary>
private IEnumerator DissolveAndDestroy()
{
// 禁用碰撞体和刚体,防止死亡过程中仍能触发碰撞或受重力下坠
foreach (var col in GetComponents<Collider>())
col.enabled = false;
foreach (var col in GetComponents<Collider2D>())
col.enabled = false;
foreach (var rb in GetComponents<Rigidbody>())
rb.isKinematic = true;
foreach (var rb in GetComponents<Rigidbody2D>())
rb.isKinematic = true;
// 禁用所有 MonoBehaviour(AI、动画等),防止死亡后仍移动/攻击
foreach (var mb in GetComponents<MonoBehaviour>())
{
if (mb != this)
mb.enabled = false;
}
// 切换所有 SpriteRenderer 到溶解材质
var renderers = GetComponentsInChildren<SpriteRenderer>();
var originalMats = new Material[renderers.Length][];
for (int i = 0; i < renderers.Length; i++)
{
originalMats[i] = renderers[i].materials;
renderers[i].materials = new Material[] { new Material(dissolveMaterial) };
}
// 动画溶解
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;
}
Destroy(gameObject);
}
}
}