chore: initial commit

This commit is contained in:
2026-05-08 11:04:00 +08:00
commit f55d2a57c3
6278 changed files with 866081 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
using System.Collections.Generic;
using UnityEngine;
namespace BaseGames.Combat
{
/// <summary>
/// 攻击判定盒。挂载在武器 Prefab 或技能 HitBox Prefab 的子节点上。
/// Phase 1 简化:直接挂在 Player Prefab 子节点 [HitBoxGround/Up/Down/Air]。
/// Collider2D 需设 IsTrigger = trueLayer = PlayerHitBox 或 EnemyHitBox。
/// </summary>
[RequireComponent(typeof(Collider2D))]
public class HitBox : MonoBehaviour
{
[SerializeField] private DamageSourceSO _defaultSource;
[SerializeField] private float _hitCooldown = 0.1f;
private DamageSourceSO _currentSource;
private Transform _attackerTransform;
private bool _isActive;
/// <summary>命中确认委托PlayerCombat / EnemyCombat 订阅)。</summary>
public System.Action<DamageInfo> OnHitConfirmed;
/// <summary>
/// 激活 HitBox。source/attacker 均可选,未传则使用 Inspector 默认值。
/// ⚠️ 不存在 Activate(float duration) 重载。
/// </summary>
public void Activate(DamageSourceSO source = null, Transform attacker = null)
{
_currentSource = source ?? _defaultSource;
_attackerTransform = attacker ?? transform;
_isActive = true;
}
public void Deactivate() => _isActive = false;
private void Awake()
{
// 确保 Collider2D 是 Trigger
var col = GetComponent<Collider2D>();
if (!col.isTrigger)
Debug.LogWarning($"[HitBox] {name}: Collider2D.isTrigger 应为 true。", this);
}
private void OnDisable()
{
_isActive = false;
_hitCooldownTimers.Clear();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (!_isActive) return;
if (_currentSource == null)
{
Debug.LogWarning($"[HitBox] {name}: 无 DamageSourceSO跳过命中。", this);
return;
}
if (!CheckCooldown(other)) return;
Vector2 knockDir = ((Vector2)other.bounds.center
- (Vector2)_attackerTransform.position).normalized;
// ⚡ 零 GCstruct 工厂,就地赋值运行时字段
var info = DamageInfo.From(_currentSource);
info.KnockbackDirection = knockDir;
info.KnockbackForce = _currentSource.KnockbackForce;
info.SourcePosition = _attackerTransform.position;
info.SourceLayer = _attackerTransform.gameObject.layer;
// ① 命中 HurtBox
var hurtBox = other.GetComponent<HurtBox>();
if (hurtBox != null)
{
hurtBox.ReceiveDamage(info);
OnHitConfirmed?.Invoke(info);
return;
}
// ② 命中 IBreakable机关/障碍物)
other.GetComponent<IBreakable>()?.TryInteract(info);
}
// ── 同目标多帧命中冷却 ────────────────────────────────────────────────
private readonly Dictionary<Collider2D, float> _hitCooldownTimers = new();
private bool CheckCooldown(Collider2D other)
{
float now = Time.time;
if (_hitCooldownTimers.TryGetValue(other, out float last) && now - last < _hitCooldown)
return false;
_hitCooldownTimers[other] = now;
return true;
}
}
}