Stash work!
This commit is contained in:
@@ -1,22 +1,46 @@
|
||||
using Core.SaveLoad;
|
||||
using Core;
|
||||
using Core.SaveLoad;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UI.CardSystem.StateMachine.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Dragging revealed state for pending cards after flip.
|
||||
/// Shows card front without badges, handles placement or return to corner.
|
||||
/// Shows card front without badges, handles transition to placement after drag release.
|
||||
/// Queries AlbumViewPage for page flip status instead of tracking state internally.
|
||||
/// </summary>
|
||||
public class CardDraggingRevealedState : AppleState, ICardStateDragHandler
|
||||
{
|
||||
private CardContext _context;
|
||||
private Vector3 _originalScale;
|
||||
|
||||
// Placement info passed from PendingFaceDownState
|
||||
private AlbumCardSlot _targetSlot;
|
||||
private bool _dragAlreadyEnded = false; // Track if drag ended before we entered this state (instant-release case)
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_context = GetComponentInParent<CardContext>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set target slot from previous state
|
||||
/// Called by PendingFaceDownState before transition
|
||||
/// </summary>
|
||||
public void SetTargetSlot(AlbumCardSlot targetSlot)
|
||||
{
|
||||
_targetSlot = targetSlot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set flag indicating drag already ended before entering this state
|
||||
/// Called by PendingFaceDownState for instant-release case
|
||||
/// </summary>
|
||||
public void SetDragAlreadyEnded(bool ended)
|
||||
{
|
||||
_dragAlreadyEnded = ended;
|
||||
}
|
||||
|
||||
public override void OnEnterState()
|
||||
{
|
||||
if (_context == null) return;
|
||||
@@ -27,6 +51,14 @@ namespace UI.CardSystem.StateMachine.States
|
||||
}
|
||||
_originalScale = _context.RootTransform.localScale;
|
||||
_context.RootTransform.localScale = _originalScale * 1.15f;
|
||||
|
||||
// Check if drag already ended before we entered this state (instant-release case)
|
||||
if (_dragAlreadyEnded)
|
||||
{
|
||||
Logging.Debug("[CardDraggingRevealedState] Drag ended before state entry - handling placement immediately");
|
||||
_dragAlreadyEnded = false; // Clear flag
|
||||
HandlePlacement();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -38,21 +70,94 @@ namespace UI.CardSystem.StateMachine.States
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle drag end - just let AlbumViewPage handle placement logic
|
||||
/// Stay in this state until AlbumViewPage transitions us after tween
|
||||
/// Handle drag end - query AlbumViewPage for page flip status and place accordingly
|
||||
/// </summary>
|
||||
public bool OnCardDragEnded(CardContext ctx)
|
||||
{
|
||||
// Don't do anything - AlbumViewPage will:
|
||||
// 1. Wait for page flip to complete
|
||||
// 2. Find the correct slot
|
||||
// 3. Tween card to slot
|
||||
// 4. Transition to PlacedInSlotState
|
||||
|
||||
// Return true to prevent default behavior
|
||||
HandlePlacement();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle card placement logic - called from OnCardDragEnded or OnEnterState (instant-release)
|
||||
/// </summary>
|
||||
private void HandlePlacement()
|
||||
{
|
||||
if (_targetSlot == null)
|
||||
{
|
||||
Logging.Warning("[CardDraggingRevealedState] No target slot set - cannot place card");
|
||||
// Return to corner
|
||||
_context.StateMachine.ChangeState("PendingFaceDownState");
|
||||
return;
|
||||
}
|
||||
|
||||
// Query AlbumViewPage for page flip status
|
||||
var albumPage = _context.AlbumViewPage;
|
||||
if (albumPage == null)
|
||||
{
|
||||
Logging.Warning("[CardDraggingRevealedState] AlbumViewPage not found - placing immediately");
|
||||
TransitionToPlacement(_context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if page is still flipping
|
||||
if (albumPage.IsPageFlipping)
|
||||
{
|
||||
// Wait for flip to complete
|
||||
Logging.Debug("[CardDraggingRevealedState] Page still flipping - waiting before placement");
|
||||
StartCoroutine(WaitForPageFlipThenPlace(_context, albumPage));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flip already done - place immediately
|
||||
Logging.Debug("[CardDraggingRevealedState] Page flip complete - placing card immediately");
|
||||
TransitionToPlacement(_context);
|
||||
}
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator WaitForPageFlipThenPlace(CardContext ctx, AlbumViewPage albumPage)
|
||||
{
|
||||
// Wait until page flip completes (max 0.5 seconds timeout)
|
||||
float timeout = 0.5f;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (albumPage.IsPageFlipping && elapsed < timeout)
|
||||
{
|
||||
yield return null;
|
||||
elapsed += Time.deltaTime;
|
||||
}
|
||||
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
Logging.Warning("[CardDraggingRevealedState] Page flip wait timed out");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Debug("[CardDraggingRevealedState] Page flip completed, placing card");
|
||||
}
|
||||
|
||||
// Now place the card
|
||||
TransitionToPlacement(ctx);
|
||||
}
|
||||
|
||||
private void TransitionToPlacement(CardContext ctx)
|
||||
{
|
||||
// Pass target slot to PlacedInSlotState
|
||||
var card = ctx.GetComponent<Card>();
|
||||
if (card != null)
|
||||
{
|
||||
var placedState = card.GetStateComponent<CardPlacedInSlotState>("PlacedInSlotState");
|
||||
if (placedState != null)
|
||||
{
|
||||
placedState.SetPlacementInfo(_targetSlot);
|
||||
}
|
||||
}
|
||||
|
||||
// Transition to PlacedInSlotState
|
||||
// The state will handle animation and finalization in OnEnterState
|
||||
ctx.StateMachine.ChangeState("PlacedInSlotState");
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_context?.RootTransform != null)
|
||||
|
||||
@@ -6,7 +6,8 @@ namespace UI.CardSystem.StateMachine.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Card is in pending face-down state in corner, awaiting drag.
|
||||
/// On drag start, triggers flip animation and transitions to revealed dragging.
|
||||
/// On drag start, queries AlbumViewPage for card data and slot, triggers page navigation,
|
||||
/// then flips and transitions to dragging revealed state.
|
||||
/// </summary>
|
||||
public class CardPendingFaceDownState : AppleState, ICardStateDragHandler
|
||||
{
|
||||
@@ -15,6 +16,8 @@ namespace UI.CardSystem.StateMachine.States
|
||||
|
||||
private CardContext _context;
|
||||
private bool _isFlipping;
|
||||
private AlbumCardSlot _targetSlot;
|
||||
private bool _dragEndedDuringFlip = false; // Track if user released before card flip animation completed
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -26,6 +29,8 @@ namespace UI.CardSystem.StateMachine.States
|
||||
if (_context == null) return;
|
||||
|
||||
_isFlipping = false;
|
||||
_targetSlot = null;
|
||||
_dragEndedDuringFlip = false;
|
||||
|
||||
// Show card back, hide card front
|
||||
if (cardBackVisual != null)
|
||||
@@ -39,37 +44,67 @@ namespace UI.CardSystem.StateMachine.States
|
||||
_context.CardDisplay.gameObject.SetActive(false);
|
||||
_context.CardDisplay.transform.localRotation = Quaternion.Euler(0, 180, 0);
|
||||
}
|
||||
|
||||
// Scale down for corner display
|
||||
_context.RootTransform.localScale = _context.OriginalScale * 0.8f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle drag start - triggers flip animation and page navigation
|
||||
/// Handle drag start - STATE ORCHESTRATES ITS OWN FLOW
|
||||
/// </summary>
|
||||
public bool OnCardDragStarted(CardContext context)
|
||||
{
|
||||
if (_isFlipping) return true; // Already handling
|
||||
|
||||
// IMPORTANT: Data must be assigned by event listeners (AlbumViewPage) BEFORE we flip
|
||||
// The event system guarantees this because events are synchronous
|
||||
if (context.CardData == null)
|
||||
// Step 1: Find AlbumViewPage
|
||||
AlbumViewPage albumPage = Object.FindFirstObjectByType<AlbumViewPage>();
|
||||
if (albumPage == null)
|
||||
{
|
||||
Logging.Warning("[CardPendingFaceDownState] OnCardDragStarted called but no CardData assigned yet!");
|
||||
return true; // Don't flip without data
|
||||
Logging.Warning("[CardPendingFaceDownState] AlbumViewPage not found!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start flip animation (data is now guaranteed to be assigned)
|
||||
|
||||
// Step 2: Ask AlbumViewPage what card to display and prompt it to rebuild
|
||||
var cardData = albumPage.GetCardForPendingSlot();
|
||||
if (cardData == null)
|
||||
{
|
||||
Logging.Warning("[CardPendingFaceDownState] No card data available from AlbumViewPage!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 3: Apply card data to context
|
||||
context.SetupCard(cardData);
|
||||
Logging.Debug($"[CardPendingFaceDownState] Assigned card data: {cardData.Name} ({cardData.Zone})");
|
||||
|
||||
// Step 4: Ask AlbumViewPage for target slot
|
||||
_targetSlot = albumPage.GetTargetSlotForCard(cardData);
|
||||
if (_targetSlot == null)
|
||||
{
|
||||
Logging.Warning($"[CardPendingFaceDownState] No slot found for card {cardData.DefinitionId}");
|
||||
// Still flip and show card, but won't be able to place it
|
||||
}
|
||||
|
||||
// Step 5: Request page navigation (no callback needed - AlbumViewPage tracks state)
|
||||
albumPage.NavigateToCardPage(cardData, null);
|
||||
|
||||
// Step 6: Start card flip animation
|
||||
StartFlipAnimation();
|
||||
|
||||
return true; // We handled it, prevent default DraggingState transition
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// We don't handle drag end in face-down state
|
||||
/// Handle drag end - if card flip animation still in progress, flag it for next state
|
||||
/// </summary>
|
||||
public bool OnCardDragEnded(CardContext context)
|
||||
{
|
||||
return false;
|
||||
if (_isFlipping)
|
||||
{
|
||||
// Card flip animation still in progress - user released immediately
|
||||
_dragEndedDuringFlip = true;
|
||||
Logging.Debug("[CardPendingFaceDownState] Drag ended during card flip - will pass to next state");
|
||||
return true; // We handled it
|
||||
}
|
||||
|
||||
return false; // Already transitioned to DraggingRevealedState, let it handle
|
||||
}
|
||||
|
||||
private void StartFlipAnimation()
|
||||
@@ -103,6 +138,24 @@ namespace UI.CardSystem.StateMachine.States
|
||||
private void OnFlipComplete()
|
||||
{
|
||||
// Transition to dragging revealed state
|
||||
// Pass target slot to next state (it will query AlbumViewPage for flip status)
|
||||
var card = _context.GetComponent<Card>();
|
||||
if (card != null)
|
||||
{
|
||||
var draggingState = card.GetStateComponent<CardDraggingRevealedState>("DraggingRevealedState");
|
||||
if (draggingState != null)
|
||||
{
|
||||
draggingState.SetTargetSlot(_targetSlot);
|
||||
|
||||
// If drag ended before we transitioned, tell next state to handle placement immediately
|
||||
if (_dragEndedDuringFlip)
|
||||
{
|
||||
draggingState.SetDragAlreadyEnded(true);
|
||||
Logging.Debug("[CardPendingFaceDownState] Passing drag-ended flag to DraggingRevealedState");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_context.StateMachine.ChangeState("DraggingRevealedState");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +1,130 @@
|
||||
using Core;
|
||||
using Core;
|
||||
using Core.SaveLoad;
|
||||
using Data.CardSystem;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UI.CardSystem.StateMachine.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Placed in slot state - card is in an album slot and can be clicked to enlarge.
|
||||
/// Manages the parent slot reference.
|
||||
/// Placed in slot state - card is being/has been placed in an album slot.
|
||||
/// SMART STATE: Handles snap-to-slot animation on entry, then finalizes placement.
|
||||
/// </summary>
|
||||
public class CardPlacedInSlotState : AppleState, ICardClickHandler
|
||||
{
|
||||
private CardContext _context;
|
||||
private AlbumCardSlot _parentSlot;
|
||||
private AlbumCardSlot _targetSlotForAnimation; // Set by DraggingRevealedState for animated placement
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_context = GetComponentInParent<CardContext>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set placement info from previous state (for animated placement from drag)
|
||||
/// </summary>
|
||||
public void SetPlacementInfo(AlbumCardSlot targetSlot)
|
||||
{
|
||||
_targetSlotForAnimation = targetSlot;
|
||||
}
|
||||
|
||||
public override void OnEnterState()
|
||||
{
|
||||
// Ensure card front is visible and facing camera
|
||||
// This is important when spawning cards directly into album (skipping booster flow)
|
||||
if (_context.CardDisplay != null)
|
||||
{
|
||||
_context.CardDisplay.gameObject.SetActive(true);
|
||||
_context.CardDisplay.transform.localRotation = Quaternion.Euler(0, 0, 0);
|
||||
}
|
||||
|
||||
Logging.Debug($"[CardPlacedInSlotState] Card placed in slot: {_context.CardData?.Name}");
|
||||
|
||||
// Card is now part of the album, no special visuals needed
|
||||
// Just wait for interaction
|
||||
// Check if this is animated placement (from drag) or direct placement (from spawn)
|
||||
if (_targetSlotForAnimation != null)
|
||||
{
|
||||
// Animated placement - play tween to slot
|
||||
Logging.Debug($"[CardPlacedInSlotState] Animating card '{_context.CardData?.Name}' to slot");
|
||||
AnimateToSlot(_targetSlotForAnimation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Direct placement (spawned in slot) - already positioned correctly
|
||||
// Disable dragging for spawned cards too
|
||||
var card = _context.GetComponent<Card>();
|
||||
if (card != null)
|
||||
{
|
||||
card.SetDraggingEnabled(false);
|
||||
}
|
||||
Logging.Debug($"[CardPlacedInSlotState] Card '{_context.CardData?.Name}' directly placed in slot");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the parent slot this card belongs to
|
||||
/// Animate card to slot position and finalize placement
|
||||
/// </summary>
|
||||
private void AnimateToSlot(AlbumCardSlot slot)
|
||||
{
|
||||
var card = _context.GetComponent<Card>();
|
||||
if (card == null) return;
|
||||
|
||||
// Reparent to slot immediately, keeping world position
|
||||
card.transform.SetParent(slot.transform, true);
|
||||
|
||||
// Tween position, scale, rotation simultaneously
|
||||
float tweenDuration = 0.4f;
|
||||
|
||||
Pixelplacement.Tween.LocalPosition(card.transform, Vector3.zero, tweenDuration, 0f, Pixelplacement.Tween.EaseOutBack);
|
||||
Pixelplacement.Tween.LocalScale(card.transform, Vector3.one, tweenDuration, 0f, Pixelplacement.Tween.EaseOutBack);
|
||||
Pixelplacement.Tween.LocalRotation(card.transform, Quaternion.identity, tweenDuration, 0f, Pixelplacement.Tween.EaseOutBack,
|
||||
completeCallback: () => FinalizePlacement(card, slot));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalize placement after animation completes
|
||||
/// </summary>
|
||||
private void FinalizePlacement(Card card, AlbumCardSlot slot)
|
||||
{
|
||||
// Ensure final position/rotation
|
||||
card.transform.localPosition = Vector3.zero;
|
||||
card.transform.localRotation = Quaternion.identity;
|
||||
|
||||
// Resize to match slot
|
||||
RectTransform cardRect = card.transform as RectTransform;
|
||||
RectTransform slotRect = slot.transform as RectTransform;
|
||||
if (cardRect != null && slotRect != null)
|
||||
{
|
||||
float targetHeight = slotRect.rect.height;
|
||||
cardRect.sizeDelta = new Vector2(cardRect.sizeDelta.x, targetHeight);
|
||||
}
|
||||
|
||||
// Set parent slot
|
||||
_parentSlot = slot;
|
||||
|
||||
// Disable dragging - cards in slots should only respond to clicks for enlargement
|
||||
card.SetDraggingEnabled(false);
|
||||
|
||||
// Notify slot
|
||||
slot.AssignCard(card);
|
||||
|
||||
// Mark as placed in inventory
|
||||
if (CardSystemManager.Instance != null)
|
||||
{
|
||||
CardSystemManager.Instance.MarkCardAsPlaced(card.CardData);
|
||||
}
|
||||
|
||||
// Notify AlbumViewPage for registration
|
||||
var albumPage = Object.FindFirstObjectByType<AlbumViewPage>();
|
||||
if (albumPage != null)
|
||||
{
|
||||
albumPage.NotifyCardPlaced(card);
|
||||
}
|
||||
|
||||
Logging.Debug($"[CardPlacedInSlotState] Card placement finalized: {card.CardData?.Name}");
|
||||
|
||||
// Clear animation target
|
||||
_targetSlotForAnimation = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the parent slot this card belongs to (for direct placement without animation)
|
||||
/// </summary>
|
||||
public void SetParentSlot(AlbumCardSlot slot)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user