Files
zeling_v2/Assets/_Game/Scripts/Enemies/Abilities/LeapAttackAbility.cs
Joywayer a1b4e629aa feat: Implement Room Streaming System
- Add RoomStreamingManager to manage room loading and unloading based on player proximity.
- Create StreamingBudgetConfigSO for memory and performance budgeting of the streaming system.
- Introduce TransitionDirector to handle seamless and atmospheric fade transitions between rooms.
- Develop WorldGraph to represent room connectivity and facilitate neighbor queries and distance calculations.
- Implement RoomNode and RoomEdge classes to structure room data and connections.
2026-05-23 19:10:29 +08:00

99 lines
3.7 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;
using UnityEngine;
using BaseGames.Combat;
namespace BaseGames.Enemies.Abilities
{
/// <summary>
/// 跳跃俯冲能力:起跳后以抛物线轨迹扑向目标,落地触发 AoE。
/// 流程:起跳预备 → 抛物线移动到目标 → 落地 AoE。
/// 使用 Rigidbody2D 直接物理推动NavAgent 在执行期间被禁用以避免冲突。
/// </summary>
[RequireComponent(typeof(Rigidbody2D))]
public sealed class LeapAttackAbility : EnemyAbilityBase
{
[Header("跳跃参数")]
[SerializeField] private float _jumpHeight = 4f;
[SerializeField] private float _maxRange = 8f;
[SerializeField] private float _windupTime = 0.35f;
[SerializeField] private float _recoveryTime = 0.4f;
[SerializeField] private LayerMask _groundMask;
[Header("落地 AoE")]
[SerializeField] private HitBox _landingHitBox;
[SerializeField] private float _hitBoxActiveTime = 0.15f;
private Rigidbody2D _rb;
private float _origGravity;
protected override void Awake()
{
base.Awake();
_rb = GetComponentInParent<Rigidbody2D>();
if (_rb != null) _origGravity = _rb.gravityScale;
}
protected override IEnumerator ExecuteCoroutine()
{
if (_rb == null || _enemy == null || _enemy.PlayerTransform == null) yield break;
var atk = _config.attackSequence != null && _config.attackSequence.Length > 0
? _config.attackSequence[0] : null;
FaceTarget(_enemy.PlayerTransform);
// Windup可选动画
if (atk != null && atk.clip != null && _animancer != null)
_animancer.Play(atk.clip);
yield return EnemyAbilityWaits.Get(_windupTime);
// 计算抛物线初速度
Vector2 from = _rb.position;
Vector2 to = _enemy.PlayerTransform.position;
float dx = Mathf.Clamp(to.x - from.x, -_maxRange, _maxRange);
float g = Mathf.Abs(Physics2D.gravity.y) * _origGravity;
float vy = Mathf.Sqrt(2f * g * Mathf.Max(0.1f, _jumpHeight));
float tUp = vy / g;
float dyDown = (from.y + _jumpHeight) - to.y;
float tDown = Mathf.Sqrt(2f * Mathf.Max(0.01f, dyDown) / g);
float total = tUp + tDown;
float vx = dx / Mathf.Max(0.1f, total);
Phase = AbilityRunState.Active;
_rb.velocity = new Vector2(vx, vy);
// 空中飞行直到接触地面
yield return null;
float airTimer = 0f;
while (airTimer < total + 0.5f)
{
airTimer += Time.fixedDeltaTime;
yield return new WaitForFixedUpdate();
if (airTimer > 0.1f && IsGrounded()) break;
}
_rb.velocity = new Vector2(0f, _rb.velocity.y);
// 落地 AoE
if (_landingHitBox != null)
{
var src = atk != null ? atk.damageSource : null;
_landingHitBox.Activate(src, _transform);
yield return EnemyAbilityWaits.Get(_hitBoxActiveTime);
_landingHitBox.Deactivate();
}
yield return EnemyAbilityWaits.Get(_recoveryTime);
}
private bool IsGrounded()
{
var hit = Physics2D.Raycast(_rb.position, Vector2.down, 0.6f, _groundMask);
return hit.collider != null;
}
protected override void OnInterrupted(InterruptReason reason)
{
if (_landingHitBox != null && _landingHitBox.IsActive) _landingHitBox.Deactivate();
}
}
}