重构
This commit is contained in:
@@ -347,6 +347,7 @@ MonoBehaviour:
|
||||
maxSightDistance: 4
|
||||
loseSightTime: 3
|
||||
listenRange: 15
|
||||
echoReleasedEvent: {fileID: 11400000, guid: 3f85d8e63d6b82342ba94a4b413c21fa, type: 2}
|
||||
bellArriveDistance: 1
|
||||
bellChaseTimeout: 10
|
||||
bellPatrolTime: 5
|
||||
@@ -385,9 +386,16 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: f9e36f6d2e0ea0541bad29e784e0841b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
onPlayerDamagedEvent: {fileID: 0}
|
||||
onPlayerDiedEvent: {fileID: 0}
|
||||
healthVar: {fileID: 0}
|
||||
maxHealthVar: {fileID: 0}
|
||||
maxHealth: 3
|
||||
deathEffect: {fileID: 0}
|
||||
isPlayer: 0
|
||||
dissolveMaterial: {fileID: 0}
|
||||
fadeDuration: 2
|
||||
damageInvincibleDuration: 2
|
||||
--- !u!114 &1893771889199554109
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -355,6 +355,10 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: f9e36f6d2e0ea0541bad29e784e0841b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
onPlayerDamagedEvent: {fileID: 11400000, guid: 1690413250c5d464eb84008d45cb88cc, type: 2}
|
||||
onPlayerDiedEvent: {fileID: 11400000, guid: 8eee0c771c042c44a88f48756f3717b5, type: 2}
|
||||
healthVar: {fileID: 11400000, guid: 6952ca1b8005ae541bf172dd398d4cc7, type: 2}
|
||||
maxHealthVar: {fileID: 11400000, guid: 6952ca1b8005ae541bf172dd398d4cc7, type: 2}
|
||||
maxHealth: 5
|
||||
deathEffect: {fileID: 4806121257990350900, guid: f19c76183b5e22e44a73655dc18f1a92, type: 3}
|
||||
isPlayer: 1
|
||||
@@ -430,6 +434,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 0a44142f1063e1d4dbab7b851d31d258, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
echoReleasedEvent: {fileID: 11400000, guid: 3f85d8e63d6b82342ba94a4b413c21fa, type: 2}
|
||||
echoKey: 101
|
||||
expandSpeed: 15
|
||||
maxRadius: 30
|
||||
@@ -441,6 +446,8 @@ MonoBehaviour:
|
||||
ringVisualWidth: 2.5
|
||||
ringYOffset: 0.1
|
||||
ringFadeTime: 3
|
||||
ringExpandSpeed: 15
|
||||
ringShader: {fileID: 4800000, guid: 67f78fa2aa44cba4cadd869535881366, type: 3}
|
||||
cooldown: 3
|
||||
--- !u!1001 &1156712605891213377
|
||||
PrefabInstance:
|
||||
|
||||
@@ -2,13 +2,23 @@ using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using GameFramework;
|
||||
using Architecture.Core;
|
||||
using Architecture.Variables;
|
||||
|
||||
namespace IndianOceanAssets.Engine2_5D
|
||||
{
|
||||
// Handles health, damage, and death for entities
|
||||
public class HealthSystem : MonoBehaviour
|
||||
{
|
||||
/// <summary>玩家受伤时触发(用于受击特效等)</summary>
|
||||
public static Action onPlayerDamaged;
|
||||
[Header("SO 事件通道(替代 static onPlayerDamaged 事件)")]
|
||||
[SerializeField] private GameEvent onPlayerDamagedEvent;
|
||||
|
||||
[Header("SO 事件通道(玩家死亡,替代直接调用 GameManager.GameOver)")]
|
||||
[SerializeField] private GameEvent onPlayerDiedEvent;
|
||||
|
||||
[Header("SO 变量(供 EnemyHealthBar / HUD 订阅,替代反射读取私有字段)")]
|
||||
[SerializeField] private IntVariable healthVar;
|
||||
[SerializeField] private IntVariable maxHealthVar;
|
||||
|
||||
[Range(1, 100)]
|
||||
[SerializeField]
|
||||
@@ -31,6 +41,7 @@ namespace IndianOceanAssets.Engine2_5D
|
||||
private bool _isDead = false; // 防止重复触发死亡
|
||||
private bool _isInvincible = false; // 无敌状态
|
||||
private float _invincibleTimer = 0f; // 无敌剩余时间(<=0 表示永久无敌)
|
||||
private bool _warnedDamaged = false; // 防止 onPlayerDamagedEvent 空引用告警刷屏
|
||||
|
||||
[Header("受伤无敌")]
|
||||
[Tooltip("玩家受伤后的无敌时间(秒)")]
|
||||
@@ -42,13 +53,33 @@ namespace IndianOceanAssets.Engine2_5D
|
||||
/// <summary>是否处于无敌状态(只读)</summary>
|
||||
public bool IsInvincible => _isInvincible;
|
||||
|
||||
/// <summary>当前血量(只读)</summary>
|
||||
public int CurrentHealth => health;
|
||||
|
||||
/// <summary>最大血量(只读)</summary>
|
||||
public int MaxHealth => maxHealth;
|
||||
|
||||
/// <summary>血量变化事件(current, max)。敌人血条等本地订阅者用于刷新显示,替代反射读取私有字段。</summary>
|
||||
public event System.Action<int, int> OnHealthChanged;
|
||||
|
||||
// 编辑器实时校验:事件字段未接线时给出黄色警告三角 + 控制台告警
|
||||
private void OnValidate()
|
||||
{
|
||||
if (isPlayer && onPlayerDamagedEvent == null)
|
||||
Debug.LogWarning($"[HealthSystem] 玩家 HealthSystem 的 On Player Damaged Event 未接线({gameObject.name})。受击泛红不会出现。", this);
|
||||
if (isPlayer && onPlayerDiedEvent == null)
|
||||
Debug.LogWarning($"[HealthSystem] 玩家 HealthSystem 的 On Player Died Event 未接线({gameObject.name})。玩家死亡不会触发过场。", this);
|
||||
}
|
||||
|
||||
// Initializes health
|
||||
private void Start()
|
||||
{
|
||||
health = maxHealth;
|
||||
if (isPlayer)
|
||||
{
|
||||
if (maxHealthVar != null) maxHealthVar.Value = maxHealth;
|
||||
if (healthVar != null) healthVar.Value = health;
|
||||
}
|
||||
}
|
||||
|
||||
// Applies damage and checks for death
|
||||
@@ -58,10 +89,20 @@ namespace IndianOceanAssets.Engine2_5D
|
||||
if (_isInvincible) return; // 无敌状态,免疫伤害
|
||||
|
||||
health -= damageAmount;
|
||||
if (isPlayer && healthVar != null) healthVar.Value = health;
|
||||
OnHealthChanged?.Invoke(health, maxHealth);
|
||||
|
||||
// 玩家受伤时触发事件(用于受击泛红特效)
|
||||
if (isPlayer && onPlayerDamaged != null)
|
||||
onPlayerDamaged.Invoke();
|
||||
if (isPlayer)
|
||||
{
|
||||
if (onPlayerDamagedEvent != null)
|
||||
onPlayerDamagedEvent.Raise();
|
||||
else if (!_warnedDamaged)
|
||||
{
|
||||
Debug.LogWarning("[HealthSystem] onPlayerDamagedEvent 未接线!受击泛红特效不会触发。请在玩家 HealthSystem 的 On Player Damaged Event 字段拖入 OnPlayerDamaged 资产。", this);
|
||||
_warnedDamaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 播放受伤音效
|
||||
if (isPlayer && AudioManager.Instance != null)
|
||||
@@ -78,8 +119,8 @@ namespace IndianOceanAssets.Engine2_5D
|
||||
|
||||
if (isPlayer)
|
||||
{
|
||||
// 玩家死亡:触发过场动画,不立即销毁(由 GameManager 处理)
|
||||
GameManager.GameOver();
|
||||
// 玩家死亡:通过 OnPlayerDied SO 事件通知 GameManager(解耦,不再直接调用单例)
|
||||
onPlayerDiedEvent?.Raise();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -213,4 +254,4 @@ namespace IndianOceanAssets.Engine2_5D
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ namespace IndianOceanAssets.Engine2_5D
|
||||
private float lastRollTime; // Timestamp of last roll
|
||||
private bool isRolling; // Is player currently rolling?
|
||||
|
||||
/// <summary>冲刺冷却剩余/总时长(供 HUD 显示,替代反射读取私有字段)。</summary>
|
||||
public (float remaining, float total) RollCooldown
|
||||
=> (Mathf.Max(0f, (lastRollTime + rollCooldown) - Time.time), rollCooldown);
|
||||
|
||||
[SerializeField] private KeyCode rollKeyCode; // Key to trigger roll
|
||||
|
||||
// Enum to switch between sword or projectile attack types
|
||||
|
||||
Reference in New Issue
Block a user