173 lines
6.2 KiB
C#
173 lines
6.2 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|