Files
zeling_v2/Assets/_Game/Scripts/Combat/HurtBoxOwnerGuard.cs
Joywayer 06048c966a feat: Add HurtBoxOwnerGuard to prevent multiple damage registrations from the same HitBox activation
- Implemented HurtBoxOwnerGuard to ensure that multiple HurtBoxes on the same character do not register damage multiple times during a single HitBox activation.
- Added custom editor for HitBox to facilitate the creation of shape colliders with HitBoxColliderProxy.
- Introduced PhysicsPerceptionSystem for enemy perception, supporting multiple detection modes including RangeCircle, BatchLOS, FanCast, and BoxCast.
- Created EnemyPatrolZone to define patrol and chase areas for enemies, allowing for shared zones among multiple enemies.
- Added BD_IsOutsideZone conditional task for Behavior Designer to check if an enemy or player is outside a defined patrol zone.
2026-06-02 16:10:44 +08:00

46 lines
2.0 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 System.Collections.Generic;
using UnityEngine;
namespace BaseGames.Combat
{
/// <summary>
/// HurtBox 所有者保护组件。防止同一角色身上的多个 HurtBox 在同一次 HitBox 激活中被重复伤害。
///
/// 工作原理:每次 HitBox 激活携带唯一 ActivationId由 HitBox.Activate() 生成递增值)。
/// HurtBox.ReceiveDamage 调用 TryRegisterHit(id) 时,同一 id 只有首次调用返回 true
/// 后续同 id 调用(来自同一角色的其他 HurtBox 子节点)返回 false 并跳过伤害流水线,
/// 从而保证"多个 HurtBox 共享同一 HP 池时,一次攻击只扣一次血"。
///
/// 生命周期:由 HurtBox.Awake() 在角色根节点自动添加(如不存在则创建)。无需手动挂载。
/// 逐帧通过 frameCount 差异懒清空处理集,零 GC 开销。
/// </summary>
[AddComponentMenu("")] // 隐藏菜单:由 HurtBox 自动管理
public sealed class HurtBoxOwnerGuard : MonoBehaviour
{
private readonly HashSet<uint> _processedIds = new(4);
private int _lastClearFrame = -1;
/// <summary>
/// 尝试注册一次命中。
/// </summary>
/// <param name="activationId">HitBox 激活 ID0 = 无追踪路径,始终允许通过)。</param>
/// <returns>true = 首次注册应继续处理伤害false = 同 id 已被处理,跳过。</returns>
public bool TryRegisterHit(uint activationId)
{
// activationId == 0LethalTrap / BodyContactDamage 等旁路路径,不做去重
if (activationId == 0) return true;
EnsureClearedThisFrame();
return _processedIds.Add(activationId);
}
private void EnsureClearedThisFrame()
{
int frame = Time.frameCount;
if (frame == _lastClearFrame) return;
_processedIds.Clear();
_lastClearFrame = frame;
}
}
}