Files
2026-09-15 10:13:58 +08:00

184 lines
6.1 KiB
C#

using System.Collections.Generic;
using SepCore.CustomUtility;
using SepCore.Definition;
using DG.Tweening;
using SepCore.Entity;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace SepCore.Entity
{
public class WeaponLightning : WeaponBase
{
[SerializeField] private float _takeOffDuration = 0.3f;
[SerializeField] private float _flyToTargetDuration = 0.2f;
[SerializeField] private float _strikeDuration = 0.1f;
[SerializeField] private float _returnDuration = 0.22f;
[SerializeField] private float _hoverHeight = 15f;
[SerializeField] private int _maxHitColliders = 32;
private Sequence _attackSequence;
private Transform _attackParent;
private Vector3 _lockedStrikePoint;
private Collider[] _hitResults;
private readonly HashSet<int> _hitEntityIds = new();
public float HitRadius => WeaponData.GetParamFloat(ParamType.HitRadius);
private IWeaponAttackEffect _attackEffect;
protected override void BuildStates()
{
RegisterState(new WeaponLightningIdleState());
RegisterState(new WeaponLightningSeekState());
RegisterState(new WeaponLightningAimState());
RegisterState(new WeaponLightningAttackState());
}
public override void Attack()
{
StopAttackTween(false);
FaceTargetImmediately();
_isAttacking = true;
_lockedStrikePoint = ResolveStrikePoint();
_attackParent = CachedTransform.parent;
CachedTransform.SetParent(null);
Vector3 takeOffPosition = CachedTransform.position;
Vector3 hoverPosition = _lockedStrikePoint + Vector3.up * Mathf.Max(0.1f, _hoverHeight);
_attackSequence = DOTween.Sequence();
_attackSequence.Append(CachedTransform.DOMove(takeOffPosition, _takeOffDuration).SetEase(Ease.OutQuad));
_attackSequence.Append(CachedTransform.DOMove(hoverPosition, _flyToTargetDuration).SetEase(Ease.OutSine));
_attackSequence.AppendCallback(() => CachedTransform.LookAt(_lockedStrikePoint));
_attackSequence.Append(CachedTransform.DOMove(_lockedStrikePoint, _strikeDuration).SetEase(Ease.InQuad));
_attackSequence.AppendCallback(() =>
{
_attackEffect.Play(this, _lockedStrikePoint, _target, HitRadius);
ApplyGroundAreaDamage();
if (_attackParent != null)
{
CachedTransform.SetParent(_attackParent);
}
});
_attackSequence.Append(CachedTransform.DOLocalMove(Vector3.zero, _returnDuration).SetEase(Ease.OutSine));
_attackSequence.AppendCallback(() =>
{
_isAttacking = false;
_attackSequence = null;
_attackParent = null;
});
}
private Vector3 ResolveStrikePoint()
{
if (_target != null && _target.Available)
{
return _target.CachedTransform.position;
}
return CachedTransform.position;
}
private void ApplyGroundAreaDamage()
{
float radius = HitRadius;
if (radius <= 0f) return;
if (TryQueueAreaCollisionQuery(_lockedStrikePoint, radius, Mathf.Max(1, _maxHitColliders)))
{
return;
}
if (_hitResults == null || _hitResults.Length == 0) return;
int hitCount = Physics.OverlapSphereNonAlloc(_lockedStrikePoint, radius, _hitResults, _hitMask,
QueryTriggerInteraction.Collide);
float radiusSqr = radius * radius;
_hitEntityIds.Clear();
for (int i = 0; i < hitCount; i++)
{
Collider collider = _hitResults[i];
if (collider == null) continue;
TargetableObject targetable = collider.GetComponentInParent<TargetableObject>();
if (targetable == null || !targetable.Available || targetable.IsDead) continue;
if (!_hitEntityIds.Add(targetable.Id)) continue;
Vector3 delta = targetable.CachedTransform.position - _lockedStrikePoint;
delta.y = 0f;
if (delta.sqrMagnitude > radiusSqr) continue;
AIUtility.PerformCollision(targetable, this);
}
}
protected override bool OnWeaponShow(object userData)
{
int colliderCapacity = Mathf.Max(1, _maxHitColliders);
if (_hitResults == null || _hitResults.Length != colliderCapacity)
{
_hitResults = new Collider[colliderCapacity];
}
_attackEffect = new LightningStrikeAttackEffect();
return true;
}
protected override void OnWeaponHide(object userData)
{
StopAttackTween(true);
_attackEffect = null;
}
protected override void OnWeaponDetach(EntityLogic parentEntity, object userData)
{
StopAttackTween(true);
base.OnWeaponDetach(parentEntity, userData);
}
protected override void OnEnabledChanged(bool enabled)
{
if (!enabled)
{
StopAttackTween(true);
}
}
private void StopAttackTween(bool resetTransform)
{
if (_attackSequence != null)
{
_attackSequence.Kill();
_attackSequence = null;
}
_isAttacking = false;
if (resetTransform)
{
if (_attackParent != null)
{
CachedTransform.SetParent(_attackParent);
CachedTransform.localPosition = Vector3.zero;
}
else if (CachedTransform.parent != null)
{
CachedTransform.localPosition = Vector3.zero;
}
CachedTransform.rotation = _cachedRotation;
}
_attackParent = null;
_hitEntityIds.Clear();
}
}
}