Files
AppleHillsProduction/docs/cards_wip/card_dragdrop_integration_summary.md
2025-11-15 20:37:02 +01:00

8.8 KiB

Card Drag/Drop Integration - Refactor Summary

What Was Changed

Files Modified:

  1. Card.cs - Now inherits from DraggableObject

    • Added drag event hooks (OnDragStartedHook, OnDragEndedHook)
    • Added setup methods for different flows (booster, album placement, album slot)
    • Changed Awake() to Initialize() to match DraggableObject pattern
  2. CardDraggingState.cs - Simplified to visual-only

    • Removed position update methods (handled by DraggableObject base)
    • Kept scale animation for visual feedback
    • Removed redundant methods (UpdateDragPosition, OnDroppedInSlot, etc.)

Files Moved to DEPRECATED:

  • CardDraggable.csDEPRECATED/ (redundant wrapper)
  • CardDraggableVisual.csDEPRECATED/ (tied to old system)
  • FlippableCard.csDEPRECATED/ (old card implementation)

Note: AlbumCardPlacementDraggable.cs remains in DragDrop/ for now (used by album corner cards)


How It Works Now

Card.cs Inheritance Chain:

Card → DraggableObject → MonoBehaviour

Card now has all DraggableObject capabilities:

  • Drag/drop detection (OnBeginDrag, OnDrag, OnEndDrag)
  • Slot detection and snapping
  • Pointer events (OnPointerEnter, OnPointerExit, etc.)
  • Enable/disable dragging via SetDraggingEnabled(bool)

Drag Event Flow:

1. Player starts dragging card
   ↓
2. DraggableObject.OnBeginDrag() fires
   ↓
3. Calls Card.OnDragStartedHook()
   ↓
4. Card transitions to DraggingState
   ↓
5. DraggingState.OnEnterState() scales card up (visual feedback)
   ↓
6. Player drags (DraggableObject handles position updates)
   ↓
7. Player releases drag
   ↓
8. DraggableObject.OnEndDrag() fires
   ↓
9. DraggableObject finds closest slot
   ↓
10. Calls Card.OnDragEndedHook()
   ↓
11. Card checks if dropped in AlbumCardSlot:
    - YES → Transition to PlacedInSlotState
    - NO → Transition to RevealedState

Setup Methods

For Booster Opening Flow:

card.SetupForBoosterReveal(cardData, isNew: true);
// - Starts in IdleState
// - Dragging DISABLED (booster cards can't be dragged)

For Album Placement Flow:

card.SetupForAlbumPlacement(cardData);
// - Starts in RevealedState
// - Dragging ENABLED (can drag to album slots)

For Cards Already in Album:

card.SetupForAlbumSlot(cardData, albumSlot);
// - Starts in PlacedInSlotState
// - Dragging DISABLED (can't drag out of album)

Integration with Existing Drag/Drop System

Works with AlbumCardSlot:

// AlbumCardSlot.cs doesn't need changes!
// It expects DraggableObject, and Card now IS a DraggableObject
public class AlbumCardSlot : DraggableSlot
{
    public bool CanAccept(DraggableObject draggable)
    {
        // Works with Card because Card inherits from DraggableObject
        if (draggable is Card card)
        {
            return CanAcceptCard(card.CardData);
        }
        return false;
    }
}

No Visual Component Needed:

  • DraggableObject can optionally use a DraggableVisual child
  • Card doesn't need one - the state machine handles all visuals
  • Card itself IS the visual representation

State Machine Integration

States that interact with drag system:

  1. RevealedState - Card waits here, dragging enabled

    • Player can click to flip (if corner card)
    • Player can drag to album slot (if placement card)
  2. DraggingState - Visual feedback during drag

    • Scales card up (1.1x by default)
    • DraggableObject handles actual drag movement
  3. PlacedInSlotState - Card placed in album

    • Dragging disabled
    • Can be clicked to enlarge

Benefits

Cleaner Architecture:

  • No wrapper scripts needed (Card, CardDraggable, CardDraggableVisual → Just Card)
  • Drag capability at top level (Card manages it directly)
  • States handle visuals only (DraggingState shows scale, not position)
  • Separation of concerns (drag logic ≠ visual logic)

Reuses Generic Base:

  • DraggableObject does all heavy lifting (snapping, slot detection, events)
  • No card-specific drag code duplication
  • Works with existing SlotContainer, DraggableSlot system

Backward Compatible:

  • Old files moved to DEPRECATED/ (not deleted)
  • AlbumCardPlacementDraggable still exists for old corner cards
  • Can migrate gradually (new Card works alongside old FlippableCard)

Testing Checklist

Booster Opening Flow:

  • Cards spawn in center (not draggable)
  • Click card → flips → enlarges
  • Tap enlarged card → shrinks to revealed state
  • Try dragging card → should be blocked (dragging disabled)

Album Placement Flow:

  • Cards spawn in corner (draggable)
  • Click card → flips → shows which card it is
  • Card enters RevealedState (draggable)
  • Drag card → enters DraggingState (scales up)
  • Drop in valid AlbumCardSlot → PlacedInSlotState
  • Drop outside slot → returns to RevealedState
  • Card in slot is NOT draggable

Album Slot Interaction:

  • Click card in slot → AlbumEnlargedState
  • Tap enlarged card → shrinks back to PlacedInSlotState
  • Card cannot be dragged out of slot

Migration Path for Old Code

Current State:

  • New Card.cs works with drag/drop
  • Old FlippableCard.cs in DEPRECATED/ (still compiles)
  • Old AlbumCardPlacementDraggable.cs still in DragDrop/ (for corner cards)

Next Steps:

  1. Update BoosterOpeningPage to use new Card.SetupForBoosterReveal()
  2. Update AlbumViewPage corner cards to use Card.SetupForAlbumPlacement()
  3. Test both flows thoroughly
  4. Once stable, delete DEPRECATED/ folder

Example Usage

BoosterOpeningPage.cs (New):

// Spawn booster cards (NOT draggable)
Card card = Instantiate(cardPrefab);
card.SetupForBoosterReveal(cardData, isNew: isNewCard);
card.Context.IsClickable = true;

// Subscribe to events
card.Context.OnFlipComplete += OnCardFlipComplete;
card.Context.OnCardInteractionComplete += OnCardComplete;

AlbumViewPage.cs (New - Corner Cards):

// Spawn unrevealed corner card (DRAGGABLE)
Card card = Instantiate(cardPrefab);
card.SetupForAlbumPlacement(cardData);

// Card can now be dragged to matching album slot
// When dropped, automatically transitions to PlacedInSlotState

AlbumViewPage.cs (New - Already Placed):

// Card already in album slot (NOT draggable)
Card card = Instantiate(cardPrefab, albumSlot.transform);
card.SetupForAlbumSlot(cardData, albumSlot);

// Card can be clicked to enlarge, but not dragged out

Technical Notes

Why Card inherits from DraggableObject:

  • Single Responsibility: Card manages its own drag capability
  • No Wrappers: Simpler prefab structure (no CardDraggable wrapper)
  • Polymorphism: AlbumCardSlot accepts DraggableObject, Card IS a DraggableObject
  • Event Integration: DraggableObject events trigger state transitions

Why DraggingState is visual-only:

  • DraggableObject handles movement: OnDrag() updates transform.position automatically
  • State shows feedback: Scaling up indicates "I'm being dragged"
  • Clean separation: Drag logic (base class) vs visual feedback (state)

Why SetDraggingEnabled():

  • Booster cards: Should never be draggable (opens in place)
  • Corner cards: Should be draggable (placement flow)
  • Album cards: Should NOT be draggable once placed (locked in slot)
  • Runtime control: Can enable/disable per card instance

Files Structure After Refactor

CardSystem/
├─ Card.cs ← NOW inherits from DraggableObject
├─ CardContext.cs
├─ CardAnimator.cs
├─ ProgressBarController.cs
├─ StateMachine/
│   ├─ States/
│   │   ├─ CardDraggingState.cs ← Simplified (visual-only)
│   │   ├─ CardRevealedState.cs ← Drag starts from here
│   │   ├─ CardPlacedInSlotState.cs ← Drag ends here (if valid slot)
│   │   └─ [other states...]
├─ DragDrop/
│   ├─ AlbumCardSlot.cs ← Works with Card (DraggableObject)
│   └─ AlbumCardPlacementDraggable.cs ← OLD system, for corner cards
└─ DEPRECATED/ ✨ NEW
    ├─ CardDraggable.cs ← Moved
    ├─ CardDraggableVisual.cs ← Moved
    └─ FlippableCard.cs ← Moved

Summary

Card.cs now inherits from DraggableObject - Owns drag capability
Drag events trigger state transitions - OnDragStarted → DraggingState
DraggingState is visual-only - Shows scale feedback
Setup methods control dragging - Enable/disable per flow
Backward compatible - Old files in DEPRECATED/
Works with existing slots - AlbumCardSlot unchanged
Cleaner architecture - No wrappers, states handle visuals

Status: Drag/Drop integration complete! Ready for testing and migration.