MusicBeat
This commit is contained in:
154
Assets/Scripts/MainGame/Items/Submodules/AuraSubmodule.cs
Normal file
154
Assets/Scripts/MainGame/Items/Submodules/AuraSubmodule.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using SLSUtilities.General;
|
||||
using SoftCircuits.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
/// <summary>
|
||||
/// 光环子模块。持续捕获指定半径内的角色,并通过 Enter / Stay / Exit 事件通知订阅方。
|
||||
/// 不使用 Data ScriptableObject,由道具在代码中直接构造。
|
||||
/// </summary>
|
||||
public class AuraSubmodule : SubmoduleBase<ItemBase>
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前处于光环内的角色集合。
|
||||
/// </summary>
|
||||
public HashSet<CharacterBase> charactersInAura = new HashSet<CharacterBase>();
|
||||
|
||||
/// <summary>
|
||||
/// 其他角色进入光环时触发,参数为进入的角色。
|
||||
/// </summary>
|
||||
public OrderedDictionary<string, PrioritizedAction<CharacterBase>> onOtherEnterAura = new();
|
||||
|
||||
/// <summary>
|
||||
/// 其他角色持续处于光环内时触发(按 stayInterval 间隔),参数为在光环内的角色。
|
||||
/// </summary>
|
||||
public OrderedDictionary<string, PrioritizedAction<CharacterBase>> onOtherStayAura = new();
|
||||
|
||||
/// <summary>
|
||||
/// 其他角色离开光环时触发,参数为离开的角色。
|
||||
/// </summary>
|
||||
public OrderedDictionary<string, PrioritizedAction<CharacterBase>> onOtherExitAura = new();
|
||||
|
||||
/// <summary>
|
||||
/// 光环半径。
|
||||
/// </summary>
|
||||
public float auraRadius;
|
||||
|
||||
/// <summary>
|
||||
/// Stay 计时器,到达 stayInterval 后对所有在光环内的角色触发 onOtherStayAura。
|
||||
/// </summary>
|
||||
public Timer stayTimer;
|
||||
|
||||
/// <summary>
|
||||
/// 物理检测的 LayerMask。
|
||||
/// </summary>
|
||||
private readonly int _detectionLayerMask;
|
||||
|
||||
private const int MaxDetectionCount = 32;
|
||||
private readonly Collider[] _overlapBuffer = new Collider[MaxDetectionCount];
|
||||
|
||||
/// <summary>
|
||||
/// 用于比较前后帧角色集合的临时缓冲。
|
||||
/// </summary>
|
||||
private readonly HashSet<CharacterBase> _currentFrameCharacters = new HashSet<CharacterBase>();
|
||||
|
||||
/// <summary>
|
||||
/// 构造光环子模块。
|
||||
/// </summary>
|
||||
/// <param name="owner">所属道具。</param>
|
||||
/// <param name="auraRadius">光环半径。</param>
|
||||
/// <param name="stayInterval">Stay 事件触发间隔(秒),默认 0.5 秒。</param>
|
||||
public AuraSubmodule(ItemBase owner, float auraRadius, float stayInterval = 0.5f) : base(owner)
|
||||
{
|
||||
this.auraRadius = auraRadius;
|
||||
|
||||
stayTimer = new Timer(stayInterval, isInfinite: true);
|
||||
stayTimer.onComplete.Add(new PrioritizedAction(OnStayTimerComplete));
|
||||
|
||||
_detectionLayerMask = LayerMask.GetMask("HurtBox");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每帧调用,驱动物理检测和事件派发。
|
||||
/// </summary>
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
DetectCharacters();
|
||||
stayTimer.Update(deltaTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有追踪状态,对仍在光环内的角色触发 Exit 事件。
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var character in charactersInAura)
|
||||
{
|
||||
if (character != null)
|
||||
{
|
||||
onOtherExitAura.Invoke(character);
|
||||
}
|
||||
}
|
||||
|
||||
charactersInAura.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行球形物理检测,比较前后帧角色集合,触发 Enter / Exit 事件。
|
||||
/// </summary>
|
||||
private void DetectCharacters()
|
||||
{
|
||||
_currentFrameCharacters.Clear();
|
||||
|
||||
Vector3 center = owner.player.transform.position;
|
||||
int hitCount = Physics.OverlapSphereNonAlloc(center, auraRadius, _overlapBuffer, _detectionLayerMask);
|
||||
|
||||
for (int i = 0; i < hitCount; i++)
|
||||
{
|
||||
CharacterBase character = _overlapBuffer[i].GetComponentInParent<CharacterBase>();
|
||||
if (character == null || character == owner.player) continue;
|
||||
|
||||
_currentFrameCharacters.Add(character);
|
||||
}
|
||||
|
||||
// 检测新进入光环的角色
|
||||
foreach (var character in _currentFrameCharacters)
|
||||
{
|
||||
if (charactersInAura.Add(character))
|
||||
{
|
||||
onOtherEnterAura.Invoke(character);
|
||||
}
|
||||
}
|
||||
|
||||
// 检测离开光环的角色(从旧集合中移除不在当前帧的角色)
|
||||
charactersInAura.RemoveWhere(character =>
|
||||
{
|
||||
if (_currentFrameCharacters.Contains(character)) return false;
|
||||
|
||||
if (character != null)
|
||||
{
|
||||
onOtherExitAura.Invoke(character);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stay 计时器到期时,对所有在光环内的角色触发 onOtherStayAura。
|
||||
/// </summary>
|
||||
private void OnStayTimerComplete()
|
||||
{
|
||||
foreach (var character in charactersInAura)
|
||||
{
|
||||
if (character != null)
|
||||
{
|
||||
onOtherStayAura.Invoke(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84bc61c526c4a824a9267b1a5c2e3ff4
|
||||
Reference in New Issue
Block a user