using UnityEngine; using BumpCombat.Constants; namespace BumpCombat.Defense { [DisallowMultipleComponent] public sealed class DefenseSpriteSequence : MonoBehaviour { private SpriteRenderer target; private Sprite[] frames; private string key; private float frameRemaining; private int frame; private Sprite[] nextFrames; private string nextKey; private bool destroyWhenFinished; private float delayRemaining; private bool animationFinished; private Vector2 travelStart; private Vector2 travelEnd; private float travelDuration; private float travelElapsed; private bool fitsLightningBeam; private Vector2 beamStart; private Vector2 beamEnd; private float beamThickness; private bool centersImpactWave; private Vector2 impactWaveCenter; private float impactWaveScale; public void Play(SpriteRenderer renderer, string sequenceKey, Sprite[] sequenceFrames, bool destroyOnFinish, string followingKey = null, Sprite[] followingFrames = null, float startDelay = 0f) { target = renderer; key = sequenceKey; frames = sequenceFrames; destroyWhenFinished = destroyOnFinish; nextKey = followingKey; nextFrames = followingFrames; delayRemaining = Mathf.Max(0f, startDelay); if (target == null || frames == null || frames.Length == 0) { enabled = false; if (destroyWhenFinished) Destroy(gameObject); return; } frame = 0; target.sprite = frames[frame]; target.enabled = delayRemaining <= 0f; frameRemaining = DefenseTowerArt.FrameSeconds(key, frame); UpdateVisualAlignment(); } public void FitLightningBeam(Vector2 start, Vector2 end, float thickness) { fitsLightningBeam = true; beamStart = start; beamEnd = end; beamThickness = thickness; UpdateVisualAlignment(); } public void CenterImpactWave(Vector2 center, float uniformScale) { centersImpactWave = true; impactWaveCenter = center; impactWaveScale = uniformScale; UpdateVisualAlignment(); } public void Travel(Vector2 start, Vector2 end, float duration) { travelStart = start; travelEnd = end; travelDuration = Mathf.Max(0.001f, duration); travelElapsed = 0f; transform.position = start; } private void Update() { if (target == null || frames == null || frames.Length == 0) { FinishSequence(); return; } if (delayRemaining > 0f) { delayRemaining -= Time.deltaTime; if (delayRemaining > 0f) return; target.enabled = true; } if (travelDuration > 0f && travelElapsed < travelDuration) { travelElapsed += Time.deltaTime; transform.position = Vector2.Lerp( travelStart, travelEnd, Mathf.Clamp01(travelElapsed / travelDuration)); } if (animationFinished) { if (travelDuration <= 0f || travelElapsed >= travelDuration) FinishSequence(); return; } frameRemaining -= Time.deltaTime; while (frameRemaining <= 0f) { frame++; if (frame >= frames.Length) { if (nextFrames != null && nextFrames.Length > 0) { frames = nextFrames; key = nextKey; nextFrames = null; frame = 0; } else { animationFinished = true; if (travelDuration <= 0f || travelElapsed >= travelDuration) FinishSequence(); return; } } target.sprite = frames[frame]; UpdateVisualAlignment(); frameRemaining += DefenseTowerArt.FrameSeconds(key, frame); } } private void UpdateVisualAlignment() { if (target == null || target.sprite == null) return; if (fitsLightningBeam) { Vector2 direction = beamEnd - beamStart; float distance = direction.magnitude; Vector2Int bounds = DefenseTowerArtBounds.LightningBeamXBounds(frame); float pixelsPerUnit = target.sprite.pixelsPerUnit; float visibleWidth = (bounds.y - bounds.x) / pixelsPerUnit; float scaleX = distance <= 0f || visibleWidth <= 0f ? 0f : distance / visibleWidth; float localStart = (bounds.x - target.sprite.pivot.x) / pixelsPerUnit * scaleX; transform.rotation = Quaternion.Euler(0f, 0f, distance > 0f ? Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg : 0f); transform.position = beamStart - (Vector2)(transform.right * localStart); transform.localScale = new Vector3(scaleX, beamThickness, 1f); } if (centersImpactWave) { transform.localScale = Vector3.one * impactWaveScale; Vector2 localCenter = (DefenseTowerArtBounds.ImpactWaveCenterPixels(frame, target.sprite) - target.sprite.pivot) / target.sprite.pixelsPerUnit; transform.position = impactWaveCenter - (Vector2)transform.TransformVector(localCenter); } } private void FinishSequence() { if (destroyWhenFinished) { Destroy(gameObject); } else { if (target != null) target.enabled = false; enabled = false; } } } }