253 lines
8.9 KiB
C#
253 lines
8.9 KiB
C#
using System;
|
|
using System.Collections;
|
|
using AppleHills.Data.CardSystem;
|
|
using Core;
|
|
using Data.CardSystem;
|
|
using Pixelplacement;
|
|
using UI.DragAndDrop.Core;
|
|
using UnityEngine;
|
|
|
|
namespace UI.CardSystem
|
|
{
|
|
/// <summary>
|
|
/// Draggable card for album reveal system.
|
|
/// Handles both tap and drag-hold interactions for revealing cards.
|
|
/// Auto-snaps to matching album slot on release/tap.
|
|
/// </summary>
|
|
public class AlbumCardPlacementDraggable : DraggableObject
|
|
{
|
|
[Header("Album Card Settings")]
|
|
[SerializeField] private FlippableCard flippableCard;
|
|
[SerializeField] private float holdRevealDelay = 0.1f;
|
|
|
|
private CardData _cardData;
|
|
private bool _isRevealed = false;
|
|
private bool _isDragRevealing = false;
|
|
private bool _waitingForPlacementTap = false;
|
|
private Coroutine _holdRevealCoroutine;
|
|
private bool _isHolding = false; // Track if pointer is currently down
|
|
|
|
// Events
|
|
public event Action<AlbumCardPlacementDraggable, CardData> OnCardRevealed;
|
|
public event Action<AlbumCardPlacementDraggable, CardData> OnCardPlacedInAlbum;
|
|
|
|
public CardData CardData => _cardData;
|
|
public bool IsRevealed => _isRevealed;
|
|
public CardZone Zone => _cardData?.Zone ?? CardZone.AppleHills;
|
|
|
|
protected override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
// Auto-find FlippableCard if not assigned
|
|
if (flippableCard == null)
|
|
{
|
|
flippableCard = GetComponent<FlippableCard>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setup the card data (stores it but doesn't reveal until tapped/dragged)
|
|
/// </summary>
|
|
public void SetupCard(CardData data)
|
|
{
|
|
_cardData = data;
|
|
|
|
if (flippableCard != null)
|
|
{
|
|
flippableCard.SetupCard(data);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reveal the card (flip to show front)
|
|
/// </summary>
|
|
public void RevealCard()
|
|
{
|
|
if (_isRevealed)
|
|
{
|
|
return;
|
|
}
|
|
_isRevealed = true;
|
|
if (flippableCard != null)
|
|
{
|
|
flippableCard.FlipToReveal();
|
|
}
|
|
OnCardRevealed?.Invoke(this, _cardData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Snap to the matching album slot
|
|
/// </summary>
|
|
public void SnapToAlbumSlot()
|
|
{
|
|
if (_cardData == null)
|
|
{
|
|
Logging.Warning("[AlbumCardPlacementDraggable] Cannot snap to slot - no card data assigned.");
|
|
return;
|
|
}
|
|
|
|
// Find all album card slots in the scene
|
|
AlbumCardSlot[] allSlots = FindObjectsByType<AlbumCardSlot>(FindObjectsSortMode.None);
|
|
|
|
AlbumCardSlot matchingSlot = null;
|
|
foreach (var slot in allSlots)
|
|
{
|
|
if (slot.CanAcceptCard(_cardData))
|
|
{
|
|
matchingSlot = slot;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (matchingSlot != null)
|
|
{
|
|
SetDraggingEnabled(false);
|
|
|
|
// NEW FLOW: Extract AlbumCard FIRST, then tween it
|
|
if (flippableCard != null)
|
|
{
|
|
AlbumCard extractedCard = flippableCard.ExtractAlbumCard(matchingSlot.transform);
|
|
|
|
if (extractedCard != null)
|
|
{
|
|
// Notify slot that card was placed
|
|
matchingSlot.OnCardPlaced(extractedCard);
|
|
|
|
// NOW tween the extracted AlbumCard into position
|
|
TweenExtractedCardToSlot(extractedCard, () =>
|
|
{
|
|
// After animation completes
|
|
Logging.Debug($"[AlbumCardPlacementDraggable] Card placement animation complete for {_cardData.Name}");
|
|
|
|
// Notify that card was placed
|
|
OnCardPlacedInAlbum?.Invoke(this, _cardData);
|
|
|
|
// Destroy this wrapper (the AlbumPlacementCard)
|
|
Destroy(gameObject);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
Logging.Warning("[AlbumCardPlacementDraggable] Failed to extract AlbumCard from wrapper!");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Logging.Warning($"[AlbumCardPlacementDraggable] Could not find matching slot for card '{_cardData.Name}' (Zone: {_cardData.Zone}, Index: {_cardData.CollectionIndex})");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tween the extracted AlbumCard into its slot position
|
|
/// Tweens from current size to slot size - AspectRatioFitter handles width
|
|
/// </summary>
|
|
private void TweenExtractedCardToSlot(AlbumCard card, System.Action onComplete)
|
|
{
|
|
Transform cardTransform = card.transform;
|
|
RectTransform cardRect = cardTransform as RectTransform;
|
|
|
|
if (cardRect != null)
|
|
{
|
|
// Get target height from slot
|
|
RectTransform slotRect = cardTransform.parent as RectTransform;
|
|
float targetHeight = slotRect != null ? slotRect.rect.height : cardRect.sizeDelta.y;
|
|
|
|
// Tween from current size to target size (AspectRatioFitter will adjust width)
|
|
Vector2 targetSize = new Vector2(cardRect.sizeDelta.x, targetHeight);
|
|
Tween.Size(cardRect, targetSize, snapDuration, 0f, Tween.EaseOutBack);
|
|
|
|
// Tween position and rotation to slot center
|
|
Tween.LocalPosition(cardRect, Vector3.zero, snapDuration, 0f, Tween.EaseOutBack);
|
|
Tween.LocalRotation(cardTransform, Quaternion.identity, snapDuration, 0f, Tween.EaseOutBack,
|
|
completeCallback: () =>
|
|
{
|
|
Logging.Debug($"[AlbumCardPlacementDraggable] Tween complete for extracted card {card.name}, final height: {cardRect.sizeDelta.y}");
|
|
onComplete?.Invoke();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// No RectTransform, just reset and call callback
|
|
cardTransform.localPosition = Vector3.zero;
|
|
cardTransform.localRotation = Quaternion.identity;
|
|
onComplete?.Invoke();
|
|
}
|
|
}
|
|
|
|
protected override void OnPointerDownHook()
|
|
{
|
|
base.OnPointerDownHook();
|
|
|
|
_isHolding = true;
|
|
|
|
// Start hold-reveal timer if card not yet revealed
|
|
if (!_isRevealed && _holdRevealCoroutine == null)
|
|
{
|
|
_holdRevealCoroutine = StartCoroutine(HoldRevealTimer());
|
|
}
|
|
}
|
|
|
|
protected override void OnPointerUpHook(bool longPress)
|
|
{
|
|
base.OnPointerUpHook(longPress);
|
|
_isHolding = false;
|
|
|
|
// Cancel hold timer if running
|
|
if (_holdRevealCoroutine != null)
|
|
{
|
|
StopCoroutine(_holdRevealCoroutine);
|
|
_holdRevealCoroutine = null;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
// Handle tap (not dragged)
|
|
if (!_wasDragged)
|
|
{
|
|
if (!_isRevealed)
|
|
{
|
|
// First tap: reveal the card
|
|
RevealCard();
|
|
_waitingForPlacementTap = true;
|
|
}
|
|
else if (_waitingForPlacementTap)
|
|
{
|
|
// Second tap: snap to slot
|
|
_waitingForPlacementTap = false;
|
|
SnapToAlbumSlot();
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
else if (_isDragRevealing)
|
|
{
|
|
// Was drag-revealed, auto-snap on release
|
|
_isDragRevealing = false;
|
|
SnapToAlbumSlot();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Coroutine to reveal card after holding for specified duration
|
|
/// </summary>
|
|
private IEnumerator HoldRevealTimer()
|
|
{
|
|
yield return new WaitForSeconds(holdRevealDelay);
|
|
|
|
// If still holding after delay, reveal the card
|
|
if (!_isRevealed && _isHolding)
|
|
{
|
|
RevealCard();
|
|
_isDragRevealing = true;
|
|
}
|
|
|
|
_holdRevealCoroutine = null;
|
|
}
|
|
}
|
|
}
|
|
|