# 灵灯碰触流程重构 ## Task 1: 灵灯只伤害第一个碰到的敌人 修改 `Assets/eco/SpiritLantern.cs` 的 `OnTriggerEnter`: ```csharp private void OnTriggerEnter(Collider other) { if (_recalled) return; // 新增:已触发则忽略后续碰撞 if (other.CompareTag("Player")) return; HealthSystem health = other.GetComponent(); if (health != null) { health.Damage(damageOnContact); StartRecallSequence(); // 改名原 Recall(),改为协程流程 } } ``` ## Task 2: 灵灯 2s 渐隐消失 + 灯光同步消失 修改 `Assets/eco/SpiritLantern.cs`,将 `Recall()` 改为分阶段流程: ```csharp private void StartRecallSequence() { if (_recalled) return; _recalled = true; // 1. 立即取消事件订阅 + 通知系统(回收灵灯名额) if (_ownerSystem != null) _ownerSystem.UnregisterLantern(this); OnLanternRecalled?.Invoke(); OnLanternRecalled = null; // 2. 禁用碰撞体,开始 2s 渐隐 GetComponent().enabled = false; StartCoroutine(FadeOutAndDestroy(2f)); } private IEnumerator FadeOutAndDestroy(float duration) { var sr = GetComponent(); var light = GetComponent(); float startAlpha = sr != null ? sr.color.a : 1f; float startIntensity = light != null ? light.Intensity : 1f; float elapsed = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; float t = elapsed / duration; if (sr != null) sr.color = new Color(sr.color.r, sr.color.g, sr.color.b, Mathf.Lerp(startAlpha, 0f, t)); if (light != null) light.SetIntensity(Mathf.Lerp(startIntensity, 0f, t)); yield return null; } Destroy(gameObject); } ``` 同时修改超时回收(`lifetime <= 0` 时)也走 `StartRecallSequence()` 而非直接销毁。 ## Task 3: 敌人被灵灯杀死时的消失特效 + 魂灵掉落 修改 `Assets/eco/SpiritLantern.cs` 的 `OnTriggerEnter`,在调用 `health.Damage()` 之前读取敌人 maxHealth 并保存敌人位置: ```csharp private void OnTriggerEnter(Collider other) { if (_recalled) return; if (other.CompareTag("Player")) return; HealthSystem health = other.GetComponent(); if (health != null) { // 在伤害前记录信息(用于掉落) Vector3 deathPos = other.transform.position; int enemyMaxHp = GetMaxHealth(health); health.Damage(damageOnContact); // 如果敌人死亡(血量<=0),生成魂灵掉落 // 注意:Die() 会 Destroy gameObject,所以位置已提前保存 if (health health <= 0) // 需要用反射或公开属性判断 SpawnSoulDrops(deathPos, enemyMaxHp); StartRecallSequence(); } } ``` 由于 `HealthSystem.health` 是 private,需要在 HealthSystem 中添加一个公开属性: ```csharp // HealthSystem.cs 新增 public bool IsDead => _isDead; public int MaxHealth => maxHealth; ``` 然后改为: ```csharp health.Damage(damageOnContact); if (health.IsDead) SpawnSoulDrops(deathPos, health.MaxHealth); ``` ## Task 4: 创建魂灵掉落物脚本 `SoulDrop.cs` 新建 `Assets/eco/SoulDrop.cs`: ```csharp public class SoulDrop : MonoBehaviour { [SerializeField] private float flyDuration = 0.8f; [SerializeField] private int scoreValue = 1; private RectTransform _targetUI; // HUD 魂灵图标位置 public void Initialize(RectTransform targetUI) { _targetUI = targetUI; StartCoroutine(FlyToHUD()); } private IEnumerator FlyToHUD() { Vector3 startPos = transform.position; // 获取目标屏幕位置 Camera cam = Camera.main; Vector3 targetScreenPos = new Vector3(_targetUI.position.x, _targetUI.position.y, cam.WorldToScreenPoint(startPos).z); Vector3 targetWorldPos = cam.ScreenToWorldPoint(targetScreenPos); float elapsed = 0f; while (elapsed < flyDuration) { elapsed += Time.deltaTime; float t = elapsed / flyDuration; // 抛物线轨迹 transform.position = Vector3.Lerp(startPos, targetWorldPos, t); transform.localScale = Vector3.one * (1f - t * 0.5f); // 缩小 yield return null; } // 到达 HUD,加分 if (ScoreManager.Instance != null) ScoreManager.Instance.AddScore(scoreValue); Destroy(gameObject); } } ``` ## Task 5: 魂灵掉落物生成逻辑 在 `SpiritLantern.cs` 中添加: ```csharp [SerializeField] private GameObject soulDropPrefab; private void SpawnSoulDrops(Vector3 position, int enemyMaxHp) { int count = enemyMaxHp * Random.Range(2, 6); // 2~5倍 RectTransform hudTarget = GameHUD.SoulIconRect; // 静态引用 for (int i = 0; i < count; i++) { Vector3 offset = new Vector3(Random.Range(-0.3f, 0.3f), Random.Range(0f, 0.3f), Random.Range(-0.3f, 0.3f)); GameObject drop = Instantiate(soulDropPrefab, position + offset, Quaternion.identity); SoulDrop soul = drop.GetComponent(); if (soul != null) soul.Initialize(hudTarget); } } ``` ## Task 6: GameHUD 暴露魂灵图标 RectTransform 修改 `Assets/UI/GameHUD.cs`,添加静态引用: ```csharp public static RectTransform SoulIconRect { get; private set; } void Start() { // ... 现有代码 ... if (soulIcon != null) SoulIconRect = soulIcon.rectTransform; } ``` ## Task 7: 创建魂灵掉落物预制体 - 创建一个小精灵 GameObject(SpriteRenderer + Collider2D trigger + SoulDrop 脚本) - 保存为 `Assets/eco/Prefabs/SoulDrop.prefab` - 将预制体引用赋给 SpiritLantern.prefab 的 `soulDropPrefab` 字段 ## Task 8: 创建魂灵掉落物 Sprite 资源 - 使用 `ImageGen` 工具生成一个小光点/魂灵图标 - 导入 Unity 并赋给 SoulDrop.prefab 的 SpriteRenderer --- ## 涉及文件汇总 | 文件 | 修改类型 | |------|---------| | `Assets/eco/SpiritLantern.cs` | 重构碰撞+渐隐+掉落逻辑 | | `Assets/2.5D Engine/Scripts/HealthSystem.cs` | 新增 `IsDead`、`MaxHealth` 公开属性 | | `Assets/UI/GameHUD.cs` | 新增 `SoulIconRect` 静态属性 | | `Assets/eco/SoulDrop.cs` | **新建** 魂灵掉落物脚本 | | `Assets/eco/Prefabs/SoulDrop.prefab` | **新建** 魂灵掉落物预制体 | | `Assets/eco/Prefabs/SpiritLantern.prefab` | 新增 `soulDropPrefab` 引用 |