灵灯系统v0.1

This commit is contained in:
2026-06-30 22:21:55 +08:00
parent bc0c85771c
commit 3c2f797f66
4 changed files with 310 additions and 1 deletions
+116
View File
@@ -0,0 +1,116 @@
using System;
using UnityEngine;
namespace IndianOceanAssets.Engine2_5D
{
/// <summary>
/// 单个灵灯的行为组件 —— 挂在灵灯 Prefab 上。
/// 放置后照亮周围区域(通过 LightSource),
/// 怪物碰触时扣 1 点血并自毁回收,
/// 存在时间到期后自动回收。
///
/// 【碰撞检测说明】
/// 灵灯自身持有 CircleCollider2D (isTrigger=true),是主动检测方。
/// 当怪物的 Collider2D 进入灵灯的触发区域时,OnTriggerEnter2D 被调用。
/// 需确保 Physics2D 碰撞矩阵中,灵灯所在 Layer 与怪物 Layer 可互相触发。
/// 灵灯不依赖 whatIsEnemy LayerMask,而是直接用 Tag/Component 判定目标。
/// </summary>
public class SpiritLantern : MonoBehaviour
{
[Header("存在时间")]
[Tooltip("灵灯放置后的存在时间(秒),到期自动回收")]
[SerializeField] private float lifetime = 10f;
[Header("伤害")]
[Tooltip("怪物碰触灵灯时受到的伤害")]
[SerializeField] private int damageOnContact = 1;
/// <summary>灵灯被回收时触发(被 SpiritLanternSystem 订阅)</summary>
public event Action OnLanternRecalled;
private bool _recalled;
private SpiritLanternSystem _ownerSystem;
/// <summary>
/// 设置灵灯的所有者系统引用,用于回收时显式取消事件订阅。
/// 由 SpiritLanternSystem.PlaceLantern() 调用。
/// </summary>
public void SetOwner(SpiritLanternSystem system)
{
_ownerSystem = system;
}
private void Update()
{
// 存在时间倒计时
lifetime -= Time.deltaTime;
if (lifetime <= 0f)
{
Recall();
}
}
/// <summary>
/// 怪物碰触灵灯时触发:扣血 + 回收灵灯。
/// 灵灯的 Trigger 主动检测进入的碰撞体,排除玩家后对怪物造成伤害。
/// </summary>
private void OnTriggerEnter2D(Collider2D other)
{
// 排除玩家(玩家 Tag 为 "Player"),避免放置时与玩家碰撞体误触发
if (other.CompareTag("Player"))
return;
// 尝试获取怪物的 HealthSystem
HealthSystem health = other.GetComponent<HealthSystem>();
if (health != null)
{
health.Damage(damageOnContact);
Recall();
}
}
/// <summary>
/// 回收灵灯:显式取消事件订阅 → 触发通知 → 销毁 GameObject。
/// 使用 _recalled 标志防止重复触发。
/// </summary>
private void Recall()
{
if (_recalled) return;
_recalled = true;
// 1. 先通过 System 显式取消事件订阅,防止内存泄漏
if (_ownerSystem != null)
{
_ownerSystem.UnregisterLantern(this);
}
// 2. 通知其他可能的订阅者(如 UI 等)
OnLanternRecalled?.Invoke();
OnLanternRecalled = null;
// 3. 销毁灵灯 GameObject
Destroy(gameObject);
}
/// <summary>
/// 安全网:如果灵灯被非正常销毁(场景卸载、外部 Destroy 等),
/// 确保事件仍然触发,避免 SpiritLanternSystem 的灵灯计数永久丢失。
/// </summary>
private void OnDestroy()
{
if (!_recalled)
{
_recalled = true;
// 先取消订阅,再触发通知
if (_ownerSystem != null)
{
_ownerSystem.UnregisterLantern(this);
}
OnLanternRecalled?.Invoke();
OnLanternRecalled = null;
}
}
}
}