using System.Collections.Generic;
using UnityEngine;
using Vanguard.Battle;
using Vanguard.Board3D;
namespace Vanguard.Board3D
{
///
/// Единый планировщик карточных перемещений. Карточки анимируются
/// Card3D, аниматор отвечает за stagger, очередь и InputLock.
///
public sealed class CardMoveAnimator
{
private sealed class Request
{
public Card3D Card;
public Vector3 FromPosition;
public Quaternion FromRotation;
public Vector3 FromScale;
public float Duration;
public float ArcHeight;
}
private readonly Queue _queue = new Queue();
private readonly List _active = new List();
private readonly InputLockService _inputLock;
private AnimationConfig _config;
private float _delay;
private bool _locked;
public CardMoveAnimator(
InputLockService inputLock,
AnimationConfig config)
{
_inputLock = inputLock;
_config = config;
}
public bool IsBusy => _queue.Count > 0 || _active.Count > 0;
public void SetConfig(AnimationConfig config)
{
_config = config;
}
public void Enqueue(
Card3D card,
Vector3 fromPosition,
Quaternion fromRotation,
Vector3 fromScale,
float duration,
float arcHeight)
{
if (card == null || card.IsDragging)
return;
EnsureLock();
_queue.Enqueue(new Request
{
Card = card,
FromPosition = fromPosition,
FromRotation = fromRotation,
FromScale = fromScale,
Duration = duration,
ArcHeight = arcHeight,
});
}
public void Tick(float deltaTime)
{
if (_active.Count > 0)
{
for (var i = _active.Count - 1; i >= 0; i--)
{
if (_active[i] == null || !_active[i].IsMoving)
_active.RemoveAt(i);
}
}
if (_queue.Count > 0)
{
_delay -= Mathf.Max(0f, deltaTime);
if (_delay <= 0f)
StartNext();
}
if (!IsBusy)
ReleaseLock();
}
public void CancelAll(bool snapCards = false)
{
_queue.Clear();
foreach (var card in _active)
{
if (card != null)
card.StopMove(snapCards);
}
_active.Clear();
_delay = 0f;
ReleaseLock();
}
private void StartNext()
{
if (_queue.Count == 0)
return;
var request = _queue.Dequeue();
var card = request.Card;
if (card == null || card.IsDragging)
{
_delay = 0f;
return;
}
card.StartArcMove(
request.FromPosition,
request.FromRotation,
request.FromScale,
request.Duration,
request.ArcHeight);
if (card.IsMoving)
_active.Add(card);
_delay = Mathf.Max(0.01f, _config != null
? _config.moveDelayBetweenCards
: 0.18f);
}
private void EnsureLock()
{
if (_locked)
return;
_inputLock?.Acquire("card-move");
_locked = true;
}
private void ReleaseLock()
{
if (!_locked)
return;
_inputLock?.Release("card-move");
_locked = false;
}
}
}